
79 changed files with 254556 additions and 716 deletions
@ -1,96 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
#include <pEp/group.h> |
|
||||
|
|
||||
#include "adapter_group.h" |
|
||||
#include "pEpLog.hh" |
|
||||
|
|
||||
#ifdef __cplusplus |
|
||||
extern "C" { |
|
||||
#endif |
|
||||
|
|
||||
/*************************************************************************************************
|
|
||||
* Group management functions |
|
||||
*************************************************************************************************/ |
|
||||
|
|
||||
DYNAMIC_API PEP_STATUS adapter_group_create( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity *group_identity, |
|
||||
pEp_identity *manager, |
|
||||
identity_list *memberlist, |
|
||||
pEp_group **group) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_create(session, group_identity, manager, memberlist, group); |
|
||||
} |
|
||||
|
|
||||
DYNAMIC_API PEP_STATUS |
|
||||
adapter_group_join(PEP_SESSION session, pEp_identity *group_identity, pEp_identity *as_member) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_join(session, group_identity, as_member); |
|
||||
} |
|
||||
|
|
||||
DYNAMIC_API PEP_STATUS |
|
||||
adapter_group_dissolve(PEP_SESSION session, pEp_identity *group_identity, pEp_identity *manager) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_dissolve(session, group_identity, manager); |
|
||||
} |
|
||||
|
|
||||
DYNAMIC_API PEP_STATUS adapter_group_invite_member( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity *group_identity, |
|
||||
pEp_identity *group_member) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_invite_member(session, group_identity, group_member); |
|
||||
} |
|
||||
|
|
||||
PEP_STATUS adapter_group_remove_member( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity *group_identity, |
|
||||
pEp_identity *group_member) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_remove_member(session, group_identity, group_member); |
|
||||
} |
|
||||
|
|
||||
DYNAMIC_API PEP_STATUS adapter_group_rating( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity *group_identity, |
|
||||
pEp_identity *manager, |
|
||||
PEP_rating *rating) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
return ::group_rating(session, group_identity, manager, rating); |
|
||||
} |
|
||||
|
|
||||
/*************************************************************************************************
|
|
||||
* Group query functions |
|
||||
*************************************************************************************************/ |
|
||||
|
|
||||
|
|
||||
//DYNAMIC_API PEP_STATUS group_query_groups(PEP_SESSION session, identity_list **groups)
|
|
||||
//{
|
|
||||
// pEpLog("called");
|
|
||||
// return PEP_STATUS_OK;
|
|
||||
//}
|
|
||||
//
|
|
||||
//DYNAMIC_API PEP_STATUS
|
|
||||
//group_query_manager(PEP_SESSION session, const pEp_identity *const group, pEp_identity **manager)
|
|
||||
//{
|
|
||||
// pEpLog("called");
|
|
||||
// return PEP_STATUS_OK;
|
|
||||
//}
|
|
||||
//
|
|
||||
//DYNAMIC_API PEP_STATUS
|
|
||||
//group_query_members(PEP_SESSION session, const pEp_identity *const group, identity_list **members)
|
|
||||
//{
|
|
||||
// pEpLog("called");
|
|
||||
// return PEP_STATUS_OK;
|
|
||||
//}
|
|
||||
|
|
||||
#ifdef __cplusplus |
|
||||
} |
|
||||
#endif |
|
@ -0,0 +1,146 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
//#include <pEp/group.h>
|
||||
|
// clang-format off
|
||||
|
#include "group_manager_api.h" |
||||
|
#include "grp_driver_replicator.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include "grp_driver_dummy.hh" |
||||
|
#include "grp_driver_engine.hh" |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
|
||||
|
Adapter::GroupDriverReplicator adapter_grp_manager{}; |
||||
|
shared_ptr<Adapter::GroupDriverDummy> grp_drv_dummy; |
||||
|
shared_ptr<Adapter::GroupDriverEngine> grp_drv_engine; |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_init() |
||||
|
{ |
||||
|
PEP_STATUS status; |
||||
|
try { |
||||
|
const string lm_dummy_db_filename = "groups.db"; |
||||
|
#ifdef WIN32 |
||||
|
const string lm_dummy_db_path = string(::per_user_directory()) + "\\" + lm_dummy_db_filename; |
||||
|
#else |
||||
|
const string lm_dummy_db_path = string(::per_user_directory()) + "/" + lm_dummy_db_filename; |
||||
|
#endif |
||||
|
|
||||
|
if(!grp_drv_dummy) { |
||||
|
grp_drv_dummy = make_shared<Adapter::GroupDriverDummy>(lm_dummy_db_path); |
||||
|
} |
||||
|
if(!grp_drv_engine) { |
||||
|
grp_drv_engine = make_shared<Adapter::GroupDriverEngine>(); |
||||
|
} |
||||
|
adapter_grp_manager.set_replication_source(*grp_drv_dummy.get()); |
||||
|
adapter_grp_manager.set_replication_destination(*grp_drv_engine.get()); |
||||
|
} catch (const std::exception &e) { |
||||
|
pEpLog(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLog("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
/*************************************************************************************************
|
||||
|
* Group management functions |
||||
|
*************************************************************************************************/ |
||||
|
DYNAMIC_API PEP_STATUS adapter_group_create( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager, |
||||
|
identity_list *memberlist) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.adapter_group_create( |
||||
|
session, |
||||
|
group_identity, |
||||
|
manager, |
||||
|
memberlist); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_dissolve( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.adapter_group_dissolve(session, group_identity, manager); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_invite_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.adapter_group_invite_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_remove_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.adapter_group_remove_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_join( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *as_member) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.adapter_group_join(session, group_identity, as_member); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
/*************************************************************************************************
|
||||
|
* Group query functions |
||||
|
*************************************************************************************************/ |
||||
|
DYNAMIC_API PEP_STATUS adapter_group_query_groups(PEP_SESSION session, identity_list **groups) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.group_query_groups(session, groups); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS |
||||
|
adapter_group_query_manager(PEP_SESSION session, const pEp_identity *const group, pEp_identity **manager) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.group_query_manager(session, group, manager); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
DYNAMIC_API PEP_STATUS adapter_group_query_members( |
||||
|
PEP_SESSION session, |
||||
|
const pEp_identity *const group, |
||||
|
identity_list **members) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
PEP_STATUS status = adapter_grp_manager.group_query_members(session, group, members); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,383 @@ |
|||||
|
#include "grp_driver_dummy.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include "utils.hh" |
||||
|
#include "std_utils.hh" |
||||
|
#include <pEp/message_api.h> |
||||
|
#include "listmanager_dummy.hh" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
bool GroupDriverDummy::log_enabled = false; |
||||
|
|
||||
|
GroupDriverDummy::GroupDriverDummy(const std::string &db_path) : |
||||
|
lmd(ListManagerDummy(db_path)) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::adapter_group_create( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager, |
||||
|
identity_list *memberlist) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!group_identity || !manager) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
if (Utils::is_c_str_empty(group_identity->address) || |
||||
|
Utils::is_c_str_empty(manager->address)) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_list{ group_identity->address }; |
||||
|
const string addr_manager{ manager->address }; |
||||
|
|
||||
|
try { |
||||
|
lmd.list_add(addr_list, addr_manager); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const AlreadyExistsException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_EXISTS; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
if (status == PEP_STATUS_OK) { |
||||
|
// Add the memberlist (if given)
|
||||
|
// Fail totally on the first member_invite() that fails
|
||||
|
const vector<pEp_identity *> cxx_memberlist = Utils::to_cxx(*memberlist); |
||||
|
for (pEp_identity *const member : cxx_memberlist) { |
||||
|
status = this->adapter_group_invite_member(session, group_identity, member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
status = status; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// The engine checks if the manager is correct for the group given
|
||||
|
// But the list manager does not require that
|
||||
|
// So, we verify that first, too. using moderator()
|
||||
|
PEP_STATUS GroupDriverDummy::adapter_group_dissolve( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!group_identity || !manager) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
if (Utils::is_c_str_empty(group_identity->address) || |
||||
|
Utils::is_c_str_empty(manager->address)) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_list{ group_identity->address }; |
||||
|
const string addr_manager{ manager->address }; |
||||
|
|
||||
|
// Check if given manager is correct for the given group
|
||||
|
string addr_manager_queried; |
||||
|
try { |
||||
|
addr_manager_queried = lmd.moderator(addr_list); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
if (status == PEP_STATUS_OK) { |
||||
|
if (addr_manager_queried != addr_manager) { |
||||
|
status = PEP_CANNOT_DISABLE_GROUP; |
||||
|
} else { |
||||
|
try { |
||||
|
lmd.list_delete(addr_list); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const MemberDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
// TODO: Silently succeed???
|
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::adapter_group_invite_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
|
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!group_identity || !group_member) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
if (Utils::is_c_str_empty(group_identity->address) || |
||||
|
Utils::is_c_str_empty(group_member->address)) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_list{ group_identity->address }; |
||||
|
const string addr_member{ group_member->address }; |
||||
|
|
||||
|
try { |
||||
|
lmd.member_add(addr_list, addr_member); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const AlreadyExistsException &e) { |
||||
|
// TODO: Silently succeed???
|
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
return PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::adapter_group_remove_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!group_identity || !group_member) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
if (Utils::is_c_str_empty(group_identity->address) || |
||||
|
Utils::is_c_str_empty(group_member->address)) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_list{ group_identity->address }; |
||||
|
const string addr_member{ group_member->address }; |
||||
|
|
||||
|
try { |
||||
|
lmd.member_remove(addr_list, addr_member); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const MemberDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
// TODO: Silently succeed???
|
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::adapter_group_join( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *as_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
// TODO: listmanager member db list_join()
|
||||
|
// PEP_STATUS status = PEP_UNKNOWN_ERROR;
|
||||
|
|
||||
|
// if (!group_identity || !group_member) {
|
||||
|
// status = PEP_ILLEGAL_VALUE;
|
||||
|
// } else {
|
||||
|
// if (Utils::is_c_str_empty(group_identity->address) ||
|
||||
|
// Utils::is_c_str_empty(group_member->address)) {
|
||||
|
// status = PEP_ILLEGAL_VALUE;
|
||||
|
// } else {
|
||||
|
// const string addr_list{ group_identity->address };
|
||||
|
// const string addr_member{ group_member->address };
|
||||
|
//
|
||||
|
// try {
|
||||
|
// lmd.member_remove(addr_list, addr_member);
|
||||
|
// status = PEP_STATUS_OK;
|
||||
|
// } catch (const MemberDoesNotExistException &e) {
|
||||
|
// pEpLogClass(Utils::nested_exception_to_string(e));
|
||||
|
// // TODO: Silently succeed???
|
||||
|
// status = PEP_STATUS_OK;
|
||||
|
// } catch (const ListDoesNotExistException &e) {
|
||||
|
// pEpLogClass(Utils::nested_exception_to_string(e));
|
||||
|
// status = PEP_GROUP_NOT_FOUND;
|
||||
|
// } catch (const exception &e) {
|
||||
|
// pEpLogClass(Utils::nested_exception_to_string(e));
|
||||
|
// status = PEP_UNKNOWN_ERROR;
|
||||
|
// } catch (...) {
|
||||
|
// pEpLogClass("unknown exception");
|
||||
|
// status = PEP_UNKNOWN_ERROR;
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::group_query_groups(PEP_SESSION session, identity_list **groups) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!session) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
vector<string> lists_queried; |
||||
|
try { |
||||
|
lists_queried = lmd.lists(); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
if (status == PEP_STATUS_OK) { |
||||
|
::identity_list *idl_groups = ::new_identity_list(nullptr); |
||||
|
for (const string &addr_list : lists_queried) { |
||||
|
::pEp_identity *grp_ident = ::new_identity( |
||||
|
addr_list.c_str(), |
||||
|
nullptr, |
||||
|
nullptr, |
||||
|
nullptr); |
||||
|
::update_identity(session, grp_ident); |
||||
|
identity_list_add(idl_groups, grp_ident); |
||||
|
} |
||||
|
*groups = idl_groups; |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::group_query_manager( |
||||
|
PEP_SESSION session, |
||||
|
const pEp_identity *const group, |
||||
|
pEp_identity **manager) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!session || !group) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_list{ group->address }; |
||||
|
string addr_manager{}; |
||||
|
try { |
||||
|
addr_manager = lmd.moderator(addr_list); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
if (status == PEP_STATUS_OK) { |
||||
|
::pEp_identity *manager_queried = ::new_identity( |
||||
|
addr_manager.c_str(), |
||||
|
nullptr, |
||||
|
nullptr, |
||||
|
nullptr); |
||||
|
::update_identity(session, manager_queried); |
||||
|
*manager = manager_queried; |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverDummy::group_query_members( |
||||
|
PEP_SESSION session, |
||||
|
const pEp_identity *const group, |
||||
|
identity_list **members) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
PEP_STATUS status = PEP_UNKNOWN_ERROR; |
||||
|
|
||||
|
if (!session || !group) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
if (Utils::is_c_str_empty(group->address)) { |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} else { |
||||
|
const string addr_grp{ group->address }; |
||||
|
vector<string> members_queried; |
||||
|
try { |
||||
|
members_queried = lmd.members(addr_grp); |
||||
|
status = PEP_STATUS_OK; |
||||
|
} catch (const ListDoesNotExistException &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_GROUP_NOT_FOUND; |
||||
|
} catch (const exception &e) { |
||||
|
pEpLogClass(Utils::nested_exception_to_string(e)); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} catch (...) { |
||||
|
pEpLogClass("unknown exception"); |
||||
|
status = PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
if (status == PEP_STATUS_OK) { |
||||
|
::identity_list *idl_members = ::new_identity_list(nullptr); |
||||
|
for (const string &addr_member : members_queried) { |
||||
|
::pEp_identity *member_ident = ::new_identity( |
||||
|
addr_member.c_str(), |
||||
|
nullptr, |
||||
|
nullptr, |
||||
|
nullptr); |
||||
|
::update_identity(session, member_ident); |
||||
|
identity_list_add(idl_members, member_ident); |
||||
|
} |
||||
|
*members = idl_members; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,69 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
#ifndef LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH |
||||
|
#define LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH |
||||
|
|
||||
|
#include "grp_manager_interface.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include "listmanager_dummy.hh" |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
class GroupDriverDummy : public GroupManagerInterface { |
||||
|
public: |
||||
|
GroupDriverDummy() = delete; |
||||
|
explicit GroupDriverDummy(const std::string &db_path); |
||||
|
|
||||
|
// GroupUpdateInterface
|
||||
|
PEP_STATUS adapter_group_create( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager, |
||||
|
::identity_list *memberlist) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_dissolve( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_invite_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_remove_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_join( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *as_member) noexcept override; |
||||
|
|
||||
|
// GroupQueryInterface
|
||||
|
PEP_STATUS group_query_groups(::PEP_SESSION session, ::identity_list **groups) noexcept override; |
||||
|
|
||||
|
PEP_STATUS group_query_manager( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::pEp_identity **manager) noexcept override; |
||||
|
|
||||
|
PEP_STATUS group_query_members( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::identity_list **members) noexcept override; |
||||
|
|
||||
|
// Logging
|
||||
|
static bool log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger{ "GroupDriverDummy", log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
ListManagerDummy lmd; |
||||
|
Adapter::pEpLog::pEpLogger &m4gic_logger_n4me = logger; |
||||
|
}; |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH
|
@ -0,0 +1,63 @@ |
|||||
|
#include "grp_driver_engine.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/group.h> |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
bool GroupDriverEngine::log_enabled = false; |
||||
|
|
||||
|
GroupDriverEngine::GroupDriverEngine() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverEngine::adapter_group_create( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager, |
||||
|
identity_list *memberlist) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return ::group_create(session, group_identity, manager, memberlist, nullptr); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverEngine::adapter_group_dissolve( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return ::group_dissolve(session, group_identity, manager); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverEngine::adapter_group_invite_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return ::group_invite_member(session, group_identity, group_member); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverEngine::adapter_group_remove_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return ::group_remove_member(session, group_identity, group_member); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverEngine::adapter_group_join( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *as_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return ::group_join(session, group_identity, as_member); |
||||
|
} |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,52 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
#ifndef LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH |
||||
|
#define LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH |
||||
|
|
||||
|
#include "grp_manager_interface.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
class GroupDriverEngine : public GroupUpdateInterface { |
||||
|
public: |
||||
|
GroupDriverEngine(); |
||||
|
|
||||
|
PEP_STATUS adapter_group_create( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager, |
||||
|
::identity_list *memberlist) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_dissolve( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_invite_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_remove_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_join( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *as_member) noexcept override; |
||||
|
|
||||
|
// Logging
|
||||
|
static bool log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger{ "GroupDriverEngine", log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
Adapter::pEpLog::pEpLogger &m4gic_logger_n4me = logger; |
||||
|
}; |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH
|
@ -0,0 +1,267 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
#include "grp_driver_replicator.hh" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
bool GroupDriverReplicator::log_enabled = false; |
||||
|
|
||||
|
GroupDriverReplicator::GroupDriverReplicator() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
/* const string lm_dummy_db_filename = "listman_dummy.db";
|
||||
|
#ifdef WIN32 |
||||
|
const string lm_dummy_db_path = string(::per_user_directory()) + "\\" + |
||||
|
lm_dummy_db_filename; |
||||
|
#else |
||||
|
const string lm_dummy_db_path = string(::per_user_directory()) + "/" + |
||||
|
lm_dummy_db_filename; |
||||
|
#endif |
||||
|
default_repl_src = make_shared<GroupDriverDummy>(lm_dummy_db_path); |
||||
|
set_replication_source(*default_repl_src); |
||||
|
|
||||
|
default_repl_dst = make_shared<GroupDriverEngine>(); |
||||
|
set_replication_destination(*default_repl_dst); |
||||
|
*/ |
||||
|
} |
||||
|
|
||||
|
void GroupDriverReplicator::set_replication_source(GroupManagerInterface &src) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
repl_src = &src; |
||||
|
} |
||||
|
|
||||
|
void GroupDriverReplicator::set_replication_destination(GroupUpdateInterface &dst) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
repl_dst = &dst; |
||||
|
} |
||||
|
|
||||
|
// GroupUpdateInterface
|
||||
|
PEP_STATUS GroupDriverReplicator::adapter_group_create( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager, |
||||
|
identity_list *memberlist) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
// Do listmanager
|
||||
|
PEP_STATUS status = repl_src->adapter_group_create( |
||||
|
session, |
||||
|
group_identity, |
||||
|
manager, |
||||
|
memberlist); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// Do engine
|
||||
|
status = repl_dst->adapter_group_create(session, group_identity, manager, memberlist); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
// Rollback listman
|
||||
|
PEP_STATUS rb_stat = repl_src->adapter_group_dissolve(session, group_identity, manager); |
||||
|
if (rb_stat != PEP_STATUS_OK) { |
||||
|
//FATAL ERROR ON ROLLBACK
|
||||
|
status = (PEP_STATUS)-9999; |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::adapter_group_dissolve( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *manager) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
// Do listmanager
|
||||
|
PEP_STATUS status = repl_src->adapter_group_dissolve(session, group_identity, manager); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// Do engine
|
||||
|
status = repl_dst->adapter_group_dissolve(session, group_identity, manager); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
// Rollback listman
|
||||
|
// TODO: ????
|
||||
|
// PEP_STATUS rb_stat = gu_listman->adapter_group_dissolve(session, group_identity, manager);
|
||||
|
// if (rb_stat != PEP_STATUS_OK) {
|
||||
|
// //FATAL ERROR ON ROLLBACK
|
||||
|
// status = (PEP_STATUS)-9999;
|
||||
|
// }
|
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::adapter_group_invite_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
// Do listmanager
|
||||
|
PEP_STATUS status = repl_src->adapter_group_invite_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// Do engine
|
||||
|
status = repl_dst->adapter_group_invite_member(session, group_identity, group_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
// Rollback
|
||||
|
PEP_STATUS rb_stat = repl_src->adapter_group_remove_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
if (rb_stat != PEP_STATUS_OK) { |
||||
|
//FATAL ERROR ON ROLLBACK
|
||||
|
status = (PEP_STATUS)-9999; |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::adapter_group_remove_member( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *group_identity, |
||||
|
pEp_identity *group_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
// Do listmanager
|
||||
|
PEP_STATUS status = repl_src->adapter_group_remove_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// Do engine
|
||||
|
status = repl_dst->adapter_group_remove_member(session, group_identity, group_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
// Rollback
|
||||
|
PEP_STATUS rb_stat = repl_src->adapter_group_invite_member( |
||||
|
session, |
||||
|
group_identity, |
||||
|
group_member); |
||||
|
if (rb_stat != PEP_STATUS_OK) { |
||||
|
//FATAL ERROR ON ROLLBACK
|
||||
|
status = (PEP_STATUS)-9999; |
||||
|
} |
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::adapter_group_join( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *as_member) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
// Do listmanager
|
||||
|
PEP_STATUS status = repl_src->adapter_group_join( |
||||
|
session, |
||||
|
group_identity, |
||||
|
as_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// Do engine
|
||||
|
status = repl_dst->adapter_group_join(session, group_identity, as_member); |
||||
|
if (status != PEP_STATUS_OK) { |
||||
|
// Rollback
|
||||
|
// TODO: need group_leave
|
||||
|
// PEP_STATUS rb_stat = repl_src->adapter_group(
|
||||
|
// session,
|
||||
|
// group_identity,
|
||||
|
// as_member);
|
||||
|
// if (rb_stat != PEP_STATUS_OK) {
|
||||
|
// //FATAL ERROR ON ROLLBACK
|
||||
|
// status = (PEP_STATUS)-9999;
|
||||
|
// }
|
||||
|
} |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
// GroupQueryInterface
|
||||
|
PEP_STATUS GroupDriverReplicator::group_query_groups( |
||||
|
PEP_SESSION session, |
||||
|
identity_list **groups) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
return repl_src->group_query_groups(session, groups); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::group_query_manager( |
||||
|
PEP_SESSION session, |
||||
|
const pEp_identity *const group, |
||||
|
pEp_identity **manager) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
return repl_src->group_query_manager(session, group, manager); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS GroupDriverReplicator::group_query_members( |
||||
|
PEP_SESSION session, |
||||
|
const pEp_identity *const group, |
||||
|
identity_list **members) noexcept |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (!has_repl_src_and_dst()) { |
||||
|
return PEP_UNKNOWN_ERROR; |
||||
|
} |
||||
|
|
||||
|
return repl_src->group_query_members(session, group, members); |
||||
|
} |
||||
|
|
||||
|
bool GroupDriverReplicator::has_repl_src_and_dst() |
||||
|
{ |
||||
|
bool ret = true; |
||||
|
if (!repl_src) { |
||||
|
ret = false; |
||||
|
pEpLogClass("Abort: no replication source (listmanager)"); |
||||
|
} |
||||
|
if (!repl_dst) { |
||||
|
ret = false; |
||||
|
pEpLogClass("Abort: no replication destination (pEpEngine)"); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,83 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
#ifndef LIBPEPADAPTER_GRP_DRIVER_REPLICATOR_HH |
||||
|
#define LIBPEPADAPTER_GRP_DRIVER_REPLICATOR_HH |
||||
|
|
||||
|
#include "grp_manager_interface.hh" |
||||
|
#include "grp_driver_engine.hh" |
||||
|
#include "grp_driver_dummy.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
class GroupDriverReplicator : public GroupManagerInterface { |
||||
|
public: |
||||
|
GroupDriverReplicator(); |
||||
|
|
||||
|
void set_replication_source(GroupManagerInterface &src); |
||||
|
void set_replication_destination(GroupUpdateInterface &dst); |
||||
|
|
||||
|
// GroupUpdateInterface
|
||||
|
PEP_STATUS adapter_group_create( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager, |
||||
|
::identity_list *memberlist) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_dissolve( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_invite_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_remove_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept override; |
||||
|
|
||||
|
PEP_STATUS adapter_group_join( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *as_member) noexcept override; |
||||
|
|
||||
|
// GroupQueryInterface
|
||||
|
PEP_STATUS group_query_groups(::PEP_SESSION session, ::identity_list **groups) noexcept override; |
||||
|
|
||||
|
PEP_STATUS group_query_manager( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::pEp_identity **manager) noexcept override; |
||||
|
|
||||
|
PEP_STATUS group_query_members( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::identity_list **members) noexcept override; |
||||
|
|
||||
|
// Logging
|
||||
|
static bool log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger{ "GroupDriverReplicator", log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
// Group replication roles
|
||||
|
// Default replication source and destination
|
||||
|
std::shared_ptr<GroupManagerInterface> default_repl_src; |
||||
|
std::shared_ptr<GroupUpdateInterface> default_repl_dst; |
||||
|
|
||||
|
// Current replication source and destination
|
||||
|
GroupManagerInterface *repl_src = nullptr; // Source needs full interface
|
||||
|
GroupUpdateInterface *repl_dst = nullptr; // Destination needs update interface only
|
||||
|
|
||||
|
// Helpers
|
||||
|
bool has_repl_src_and_dst(); |
||||
|
// Logging
|
||||
|
Adapter::pEpLog::pEpLogger &m4gic_logger_n4me = logger; |
||||
|
}; |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_GRP_DRIVER_REPLICATOR_HH
|
@ -0,0 +1,66 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_GRP_MANAGER_INTERFACE_HH |
||||
|
#define LIBPEPADAPTER_GRP_MANAGER_INTERFACE_HH |
||||
|
|
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
class GroupUpdateInterface { |
||||
|
public: |
||||
|
virtual PEP_STATUS adapter_group_create( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager, |
||||
|
::identity_list *memberlist) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS adapter_group_dissolve( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *manager) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS adapter_group_invite_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS adapter_group_remove_member( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *group_member) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS adapter_group_join( |
||||
|
::PEP_SESSION session, |
||||
|
::pEp_identity *group_identity, |
||||
|
::pEp_identity *as_member) noexcept = 0; |
||||
|
|
||||
|
private: |
||||
|
}; |
||||
|
|
||||
|
class GroupQueryInterface { |
||||
|
public: |
||||
|
virtual PEP_STATUS group_query_groups( |
||||
|
::PEP_SESSION session, |
||||
|
::identity_list **groups) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS group_query_manager( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::pEp_identity **manager) noexcept = 0; |
||||
|
|
||||
|
virtual PEP_STATUS group_query_members( |
||||
|
::PEP_SESSION session, |
||||
|
const ::pEp_identity *const group, |
||||
|
::identity_list **members) noexcept = 0; |
||||
|
|
||||
|
private: |
||||
|
}; |
||||
|
|
||||
|
class GroupManagerInterface : public GroupUpdateInterface, public GroupQueryInterface { |
||||
|
}; |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_GRP_MANAGER_INTERFACE_HH
|
File diff suppressed because it is too large
@ -0,0 +1,367 @@ |
|||||
|
#include "listmanager_dummy.hh" |
||||
|
#include "pEpSQLite.hh" |
||||
|
#include <exception> |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace pEp { |
||||
|
bool ListManagerDummy::log_enabled = false; |
||||
|
|
||||
|
// public
|
||||
|
ListManagerDummy::ListManagerDummy(const string& db_path) : db(pEpSQLite(db_path)) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
void ListManagerDummy::ensure_db_initialized() |
||||
|
{ |
||||
|
if (!db.is_open()) { |
||||
|
is_db_initialized = false; |
||||
|
try { |
||||
|
db.create_or_open_db(); |
||||
|
} catch (...) { |
||||
|
db.close_db(); |
||||
|
DBException e{ "ListManagerDummy - error opening db" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
if (!is_db_initialized) { |
||||
|
try { |
||||
|
db_config(); |
||||
|
create_tables(); |
||||
|
} catch (...) { |
||||
|
db.close_db(); |
||||
|
DBException e{ "ListManagerDummy - db init failed" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
is_db_initialized = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
void ListManagerDummy::db_config() |
||||
|
{ |
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "PRAGMA foreign_keys=ON"; |
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy - db config failed" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
void ListManagerDummy::create_tables() |
||||
|
{ |
||||
|
try { |
||||
|
string sql; |
||||
|
|
||||
|
sql = "CREATE TABLE IF NOT EXISTS lists(" |
||||
|
"address TEXT NOT NULL," |
||||
|
"moderator_address TEXT NOT NULL," |
||||
|
"PRIMARY KEY(address));"; |
||||
|
db.execute(sql); |
||||
|
|
||||
|
sql = "CREATE TABLE IF NOT EXISTS member_of(" |
||||
|
"address TEXT NOT NULL," |
||||
|
"list_address TEXT NOT NULL," |
||||
|
"PRIMARY KEY (address, list_address)," |
||||
|
"FOREIGN KEY(list_address) REFERENCES lists(address) ON DELETE CASCADE);"; |
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e("ListManagerDummy - create tables failed"); |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::close_db() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
db.close_db(); |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::delete_db() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
try { |
||||
|
db.delete_db(); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: delete_db() failed" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::list_add(const std::string& addr_list, const std::string& addr_mgr) |
||||
|
{ |
||||
|
pEpLogClass("list_add(addr_list: \"" + addr_list + "\", addr_mgr: \"" + addr_mgr + "\")"); |
||||
|
if (list_exists(addr_list)) { |
||||
|
AlreadyExistsException e{ "list_add(addr_list: \"" + addr_list + "\", addr_mgr: \"" + |
||||
|
addr_mgr + "\") - List already exists" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
string sql = "INSERT INTO lists(address, moderator_address) VALUES ('" + addr_list + |
||||
|
"','" + addr_mgr + "');"; |
||||
|
|
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: list_add(addr_list: \"" + addr_list + |
||||
|
"\"\taddr_mgr: \"" + addr_mgr + "\") - failed with exception" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::list_delete(const std::string& addr_list) |
||||
|
{ |
||||
|
pEpLogClass("list_delete(addr_list: \"" + addr_list + "\")"); |
||||
|
if (!list_exists(addr_list)) { |
||||
|
ListDoesNotExistException e{ "list_delete(addr_list: \"" + addr_list + |
||||
|
"\") - List does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "DELETE FROM lists WHERE lists.address = '" + addr_list + "';"; |
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: list_delete(addr_list: \"" + addr_list + |
||||
|
"\") - failed with exception" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::member_add(const std::string& addr_list, const std::string& addr_member) |
||||
|
{ |
||||
|
pEpLogClass( |
||||
|
"member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + addr_member + "\")"); |
||||
|
if (!list_exists(addr_list)) { |
||||
|
ListDoesNotExistException e{ "member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + |
||||
|
addr_member + "\") - list does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
if (member_exists(addr_list, addr_member)) { |
||||
|
AlreadyExistsException e{ "member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + |
||||
|
addr_member + "\") - member already exists" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
string sql = "INSERT INTO member_of(address, list_address) VALUES ('" + addr_member + |
||||
|
"', '" + addr_list + "');"; |
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: member_add(addr_list: \"" + addr_list + |
||||
|
"\", addr_member: \"" + addr_member + "\") - failed with exception" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void ListManagerDummy::member_remove(const std::string& addr_list, const std::string& addr_member) |
||||
|
{ |
||||
|
pEpLogClass( |
||||
|
"member_remove(addr_list: \"" + addr_list + "\", addr_member: '\"" + addr_member + "\")"); |
||||
|
if (!list_exists(addr_list)) { |
||||
|
ListDoesNotExistException e{ "member_remove(addr_list: \"" + addr_list + |
||||
|
"\", addr_member: '\"" + addr_member + |
||||
|
"\") - list does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
if (!member_exists(addr_list, addr_member)) { |
||||
|
MemberDoesNotExistException e{ "member_remove(addr_list: \"" + addr_list + |
||||
|
"\", addr_member: '\"" + addr_member + |
||||
|
"\") - member does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "DELETE FROM member_of WHERE (member_of.address = '" + addr_member + |
||||
|
"') AND (member_of.list_address = '" + addr_list + "');"; |
||||
|
db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: member_remove(" + addr_list + ", " + addr_member + |
||||
|
") - failed with exception" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
std::vector<std::string> ListManagerDummy::lists() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
ensure_db_initialized(); |
||||
|
vector<string> ret; |
||||
|
ResultSet rs; |
||||
|
|
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "SELECT address FROM lists"; |
||||
|
rs = db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: lists() failed" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
|
||||
|
for (const RSRecord& rec : rs) { |
||||
|
ret.push_back(rec.at("address")); |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
std::string ListManagerDummy::moderator(const std::string& addr_list) |
||||
|
{ |
||||
|
pEpLogClass("moderator(list_address:\"" + addr_list + "\")"); |
||||
|
if (!list_exists(addr_list)) { |
||||
|
ListDoesNotExistException e{ "moderator(list_address:\"" + addr_list + |
||||
|
"\") - List does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
string ret; |
||||
|
ResultSet rs; |
||||
|
|
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "SELECT moderator_address FROM lists " |
||||
|
"WHERE lists.address = '" + |
||||
|
addr_list + "';"; |
||||
|
rs = db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: moderator(list_address:\"" + addr_list + |
||||
|
"\") - failed" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
|
||||
|
if (!rs.empty()) { |
||||
|
for (const RSRecord& rec : rs) { |
||||
|
ret = rec.at("moderator_address"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
std::vector<std::string> ListManagerDummy::members(const std::string& addr_list) |
||||
|
{ |
||||
|
pEpLogClass("members(list_address:\"" + addr_list + "\")"); |
||||
|
if (!list_exists(addr_list)) { |
||||
|
ListDoesNotExistException e{ "members(list_address:\"" + addr_list + |
||||
|
"\") - List does not exist" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
vector<string> ret; |
||||
|
ResultSet rs; |
||||
|
|
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "SELECT address FROM member_of " |
||||
|
"WHERE list_address = '" + |
||||
|
addr_list + "'"; |
||||
|
rs = db.execute(sql); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: members(list_address:\"" + addr_list + "\")" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
|
||||
|
if (!rs.empty()) { |
||||
|
for (const RSRecord& rec : rs) { |
||||
|
ret.push_back(rec.at("address")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool ListManagerDummy::list_exists(const std::string& addr_list) |
||||
|
{ |
||||
|
pEpLogClass("list_exists(addr_list:\"" + addr_list + "\")"); |
||||
|
bool ret{ false }; |
||||
|
ensure_db_initialized(); |
||||
|
|
||||
|
ResultSet rs; |
||||
|
int rescount = 0; |
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "SELECT COUNT(address) AS rescount " |
||||
|
"FROM lists " |
||||
|
"WHERE address = '" + |
||||
|
addr_list + "';"; |
||||
|
rs = db.execute(sql); |
||||
|
rescount = pEpSQLite::eval_sql_count(rs, "rescount"); |
||||
|
} catch (...) { |
||||
|
DBException e{ "ListManagerDummy: list_exists(addr_list:\"" + addr_list + "\")" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
// Check FATAL inconsistency
|
||||
|
if (rescount > 1) { |
||||
|
DBException e{ "ListManagerDummy: list_exists(addr_list:\"" + addr_list + |
||||
|
"\") - FATAL DB CONSTRAINT ERROR: list exists more than once" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
|
||||
|
if (rescount == 1) { |
||||
|
ret = true; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool ListManagerDummy::member_exists(const std::string& addr_list, const std::string& addr_member) |
||||
|
{ |
||||
|
pEpLogClass( |
||||
|
"member_exists(addr_list:\"" + addr_list + "\", addr_member:\"" + addr_member + "\")"); |
||||
|
bool ret{ false }; |
||||
|
ensure_db_initialized(); |
||||
|
|
||||
|
ResultSet rs; |
||||
|
int rescount = 0; |
||||
|
try { |
||||
|
string sql; |
||||
|
sql = "SELECT COUNT(address) AS rescount " |
||||
|
"FROM member_of " |
||||
|
"WHERE (address = '" + |
||||
|
addr_member + "' AND list_address = '" + addr_list + "');"; |
||||
|
rs = db.execute(sql); |
||||
|
rescount = pEpSQLite::eval_sql_count(rs, "rescount"); |
||||
|
} catch (...) { |
||||
|
DBException e{ "member_exists(addr_list:\"" + addr_list + "\", addr_member:\"" + |
||||
|
addr_member + "\")" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
// Check FATAL inconsistency
|
||||
|
if (rescount > 1) { |
||||
|
DBException e{ "member_exists(addr_list:\"" + addr_list + "\", addr_member:\"" + |
||||
|
addr_member + |
||||
|
"\") - FATAL DB CONSTRAINT ERROR: list exists more than once" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
|
||||
|
if (rescount == 1) { |
||||
|
ret = true; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// public
|
||||
|
ListManagerDummy::~ListManagerDummy() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
db.close_db(); |
||||
|
} |
||||
|
} // namespace pEp
|
@ -0,0 +1,63 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_LISTMANAGER_DUMMY_HH |
||||
|
#define LIBPEPADAPTER_LISTMANAGER_DUMMY_HH |
||||
|
|
||||
|
#include "pEpSQLite.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <vector> |
||||
|
#include <string> |
||||
|
|
||||
|
namespace pEp { |
||||
|
class ListManagerDummy { |
||||
|
public: |
||||
|
ListManagerDummy() = delete; |
||||
|
explicit ListManagerDummy(const std::string& db_path); |
||||
|
// Update
|
||||
|
void list_add(const std::string& addr_list, const std::string& addr_mgr); |
||||
|
void list_delete(const std::string& addr_list); |
||||
|
void member_add(const std::string& addr_list, const std::string& addr_member); |
||||
|
void member_remove(const std::string& addr_list, const std::string& addr_member); |
||||
|
// Query
|
||||
|
std::vector<std::string> lists(); |
||||
|
std::string moderator(const std::string& addr_list); |
||||
|
std::vector<std::string> members(const std::string& addr_list); |
||||
|
bool list_exists(const std::string& addr_list); |
||||
|
bool member_exists(const std::string& addr_list, const std::string& addr_member); |
||||
|
// db
|
||||
|
void close_db(); |
||||
|
void delete_db(); |
||||
|
// Logging
|
||||
|
static bool log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger{ "ListManagerDummy", log_enabled }; |
||||
|
~ListManagerDummy(); |
||||
|
|
||||
|
private: |
||||
|
pEpSQLite db; |
||||
|
bool is_db_initialized{ false }; |
||||
|
void ensure_db_initialized(); |
||||
|
void db_config(); |
||||
|
void create_tables(); |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
}; |
||||
|
|
||||
|
class DBException : public std::runtime_error { |
||||
|
public: |
||||
|
explicit DBException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
class ListDoesNotExistException : public std::runtime_error { |
||||
|
public: |
||||
|
explicit ListDoesNotExistException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
class MemberDoesNotExistException : public std::runtime_error { |
||||
|
public: |
||||
|
explicit MemberDoesNotExistException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
class AlreadyExistsException : public std::runtime_error { |
||||
|
public: |
||||
|
explicit AlreadyExistsException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_LISTMANAGER_DUMMY_HH
|
@ -0,0 +1,167 @@ |
|||||
|
#include "pEpSQLite.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <iostream> |
||||
|
#include <cstdio> |
||||
|
#include <stdexcept> |
||||
|
#include <string> |
||||
|
#include <cstring> |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace pEp { |
||||
|
bool pEpSQLite::log_enabled = false; |
||||
|
|
||||
|
pEpSQLite::pEpSQLite(const std::string &db_path) : db_path(db_path) |
||||
|
{ |
||||
|
pEpLogClass("called with db_path: " + db_path + ""); |
||||
|
} |
||||
|
|
||||
|
void pEpSQLite::create_or_open_db() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
int rc{ ::sqlite3_open(db_path.c_str(), &db) }; |
||||
|
|
||||
|
if (rc) { |
||||
|
runtime_error e{ "pEpSQLite: create_or_open_db(\"" + db_path + |
||||
|
"\") - failed with sqlite3 error: " + std::to_string(rc) + " - " + |
||||
|
::sqlite3_errmsg(db) }; |
||||
|
close_db(); |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
string pEpSQLite::get_db_path() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return db_path; |
||||
|
} |
||||
|
|
||||
|
void pEpSQLite::close_db() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (db != nullptr) { |
||||
|
::sqlite3_close(db); |
||||
|
db = nullptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool pEpSQLite::is_open() const |
||||
|
{ |
||||
|
if (db == nullptr) { |
||||
|
return false; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void pEpSQLite::delete_db() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
close_db(); |
||||
|
int status = remove(db_path.c_str()); |
||||
|
if (status) { |
||||
|
runtime_error e{ "pEpSQLite: delete_db(\"" + db_path + "\"): failed with error: " + |
||||
|
std::to_string(status) + " - " + strerror(errno) }; |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int pEpSQLite::callback(void *obj, int argc, char **argv, char **azColName) |
||||
|
{ |
||||
|
RSRecord record; |
||||
|
for (int col = 0; col < argc; col++) { |
||||
|
const string key = string{ azColName[col] }; |
||||
|
// TODO: NULL is not correct, could be a valid value
|
||||
|
const string val = string{ argv[col] ? argv[col] : "NULL" }; |
||||
|
record.insert({ key, val }); |
||||
|
} |
||||
|
(static_cast<pEpSQLite *>(obj))->resultset.push_back(record); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
ResultSet pEpSQLite::execute(const string &stmt) |
||||
|
{ |
||||
|
if (!is_open()) { |
||||
|
DBNotOpenException e{ "pEpSQLite: execute() failed - db is not open:" }; |
||||
|
throw(e); |
||||
|
} else { |
||||
|
pEpLogClass("called"); |
||||
|
this->resultset.clear(); |
||||
|
char *zErrMsg = nullptr; |
||||
|
int rc = ::sqlite3_exec( |
||||
|
db, |
||||
|
stmt.c_str(), |
||||
|
(int (*)(void *, int, char **, char **)) & callback, |
||||
|
this, |
||||
|
&zErrMsg); |
||||
|
if (rc != SQLITE_OK) { |
||||
|
if (rc == SQLITE_CONSTRAINT) { |
||||
|
ConstraintException e{ "pEpSQLite: execute() failed with sqlite error: " + |
||||
|
std::to_string(rc) + " - " + string(zErrMsg) }; |
||||
|
::sqlite3_free(zErrMsg); |
||||
|
throw(e); |
||||
|
} |
||||
|
runtime_error e{ "pEpSQLite: execute() failed with sqlite error: " + |
||||
|
std::to_string(rc) + " - " + string(zErrMsg) }; |
||||
|
::sqlite3_free(zErrMsg); |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
return resultset; |
||||
|
} |
||||
|
|
||||
|
// Utils
|
||||
|
string pEpSQLite::to_string(const RSRecord &rec) |
||||
|
{ |
||||
|
stringstream ss; |
||||
|
for (const auto &col : rec) { |
||||
|
ss << "[\"" << col.first << "\"] = \"" << col.second << "\"" << endl; |
||||
|
} |
||||
|
return ss.str(); |
||||
|
} |
||||
|
|
||||
|
string pEpSQLite::to_string(const ResultSet &rs) |
||||
|
{ |
||||
|
stringstream ss; |
||||
|
ss << "ROWCOUNT: " << rs.size() << endl; |
||||
|
int i = 0; |
||||
|
for (const RSRecord &rec : rs) { |
||||
|
ss << "ROW[" << i << "]" << endl << to_string(rec); |
||||
|
i++; |
||||
|
} |
||||
|
return ss.str(); |
||||
|
} |
||||
|
|
||||
|
//Helper
|
||||
|
int pEpSQLite::eval_sql_count(const ResultSet& rs, const string& countfieldname) |
||||
|
{ |
||||
|
int rescount = 0; |
||||
|
// Get row
|
||||
|
RSRecord rec{}; |
||||
|
if (rs.size() != 1) { |
||||
|
runtime_error e{ "ListManagerDummy: eval_sql_count() - row count != 1" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
try { |
||||
|
rec = rs.at(0); |
||||
|
} catch (...) { |
||||
|
runtime_error e{ "ListManagerDummy: eval_sql_count() - cant get row nr 0" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
// Get field
|
||||
|
try { |
||||
|
rescount = stoi(rec.at(countfieldname)); |
||||
|
} catch (...) { |
||||
|
runtime_error e{ "ListManagerDummy: eval_sql_count() - field not existing" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
return rescount; |
||||
|
} |
||||
|
|
||||
|
pEpSQLite::~pEpSQLite() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
close_db(); |
||||
|
} |
||||
|
} // namespace pEp
|
@ -0,0 +1,64 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
#ifndef LIBPEPADAPTER_PEPSQLITE_HH |
||||
|
#define LIBPEPADAPTER_PEPSQLITE_HH |
||||
|
|
||||
|
#include "internal/sqlite3.h" |
||||
|
#include "pEpLog.hh" |
||||
|
#include <iostream> |
||||
|
#include <vector> |
||||
|
#include <map> |
||||
|
|
||||
|
|
||||
|
using ResultSet = std::vector<std::map<std::string, std::string>>; |
||||
|
using RSRecord = std::map<std::string, std::string>; |
||||
|
|
||||
|
namespace pEp { |
||||
|
class pEpSQLite { |
||||
|
public: |
||||
|
pEpSQLite() = delete; |
||||
|
|
||||
|
// The database file as a constant for the obj lifetime
|
||||
|
explicit pEpSQLite(const std::string& db_path); |
||||
|
std::string get_db_path() const; |
||||
|
|
||||
|
// Creates the database file not existsing
|
||||
|
// Will not create any dirs
|
||||
|
void create_or_open_db(); |
||||
|
void close_db(); |
||||
|
bool is_open() const; |
||||
|
|
||||
|
// Delete the database file
|
||||
|
void delete_db(); |
||||
|
ResultSet execute(const std::string& stmt); |
||||
|
|
||||
|
// Utils
|
||||
|
static std::string to_string(const RSRecord& rec); |
||||
|
static std::string to_string(const ResultSet& rs); |
||||
|
static int eval_sql_count(const ResultSet& rs, const std::string& countfieldname); |
||||
|
|
||||
|
// Logging
|
||||
|
static bool log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger{ "pEpSQLite", log_enabled }; |
||||
|
~pEpSQLite(); |
||||
|
|
||||
|
private: |
||||
|
::sqlite3* db = nullptr; |
||||
|
std::string db_path; |
||||
|
ResultSet resultset; |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
static int callback(void* obj, int argc, char** argv, char** azColName); |
||||
|
}; |
||||
|
|
||||
|
class DBNotOpenException : public std::runtime_error { |
||||
|
public: |
||||
|
DBNotOpenException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
|
||||
|
class ConstraintException : public std::runtime_error { |
||||
|
public: |
||||
|
ConstraintException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_PEPSQLITE_HH
|
File diff suppressed because it is too large
@ -0,0 +1,297 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "std_utils.hh" |
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include <cstdio> |
||||
|
#include <cerrno> |
||||
|
#include <cmath> |
||||
|
#include <algorithm> |
||||
|
#include <thread> |
||||
|
#include <random> |
||||
|
#include <cstring> |
||||
|
#ifndef WIN32 |
||||
|
#include <dirent.h> |
||||
|
#include <sys/stat.h> |
||||
|
#endif |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Utils { |
||||
|
bool is_c_str_empty(const char *str) |
||||
|
{ |
||||
|
if (str == nullptr) { |
||||
|
return true; |
||||
|
} |
||||
|
string tmp{ str }; |
||||
|
if (tmp.empty()) { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
string nested_exception_to_string(const exception &e, int level, string src) |
||||
|
{ |
||||
|
src += string(level, ' ') + "exception: " + e.what() + "\n"; |
||||
|
try { |
||||
|
rethrow_if_nested(e); |
||||
|
} catch (const exception &e) { |
||||
|
src = nested_exception_to_string(e, level + 1, src); |
||||
|
} catch (...) { |
||||
|
} |
||||
|
return src; |
||||
|
} |
||||
|
|
||||
|
// File utils
|
||||
|
bool path_exists(const string &filename) |
||||
|
{ |
||||
|
ifstream ifile(filename.c_str()); |
||||
|
return (bool)ifile; |
||||
|
} |
||||
|
|
||||
|
void path_delete(const string &filename) |
||||
|
{ |
||||
|
int status = remove(filename.c_str()); |
||||
|
if (status) { |
||||
|
runtime_error e{ string("path_delete(\"" + filename + "\") - " + strerror(errno)) }; |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
bool path_is_dir(const string &path) |
||||
|
{ |
||||
|
bool ret = false; |
||||
|
struct stat statbuf; |
||||
|
if (stat(path.c_str(), &statbuf) != 0) { |
||||
|
runtime_error e{ "path_is_dir(\"" + path + "\") - " + strerror(errno) }; |
||||
|
throw(e); |
||||
|
} |
||||
|
if (S_ISDIR(statbuf.st_mode)) { |
||||
|
ret = true; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void path_delete_all(const string &path) |
||||
|
{ |
||||
|
try { |
||||
|
if (!path_is_dir(path)) { |
||||
|
path_delete(path); |
||||
|
} else { |
||||
|
vector<string> dirlist = dir_list_all(path); |
||||
|
if (dirlist.empty()) { |
||||
|
path_delete(path); |
||||
|
} else { |
||||
|
for (const string &filename : dirlist) { |
||||
|
string newpath = path + "/" + filename; |
||||
|
path_delete_all(newpath); |
||||
|
} |
||||
|
path_delete(path); |
||||
|
} |
||||
|
} |
||||
|
} catch (...) { |
||||
|
runtime_error e{ "path_delete_all(\"" + path + "\")" }; |
||||
|
throw_with_nested(e); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
ofstream file_create(const string &filename) |
||||
|
{ |
||||
|
ofstream outfile{ filename }; |
||||
|
return outfile; |
||||
|
} |
||||
|
|
||||
|
std::string file_read(const std::string &filename) |
||||
|
{ |
||||
|
auto ss = ostringstream{}; |
||||
|
ifstream input_file(filename); |
||||
|
if (!input_file.is_open()) { |
||||
|
runtime_error e{ "Could not open the file: " + filename }; |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
ss << input_file.rdbuf(); |
||||
|
return ss.str(); |
||||
|
} |
||||
|
|
||||
|
void path_ensure_not_existing(const string &path) |
||||
|
{ |
||||
|
while (path_exists(path)) { |
||||
|
path_delete_all(path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
void dir_create(const string &dirname, const mode_t mode) |
||||
|
{ |
||||
|
if (mkdir(dirname.c_str(), mode) != 0) { |
||||
|
runtime_error e{ string("dir_create(\"" + dirname + "\") - " + strerror(errno)) }; |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void dir_ensure(const std::string &path) |
||||
|
{ |
||||
|
if (!Utils::path_exists(path)) { |
||||
|
Utils::dir_create(path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void dir_recreate(const std::string &path) |
||||
|
{ |
||||
|
Utils::path_ensure_not_existing(path); |
||||
|
Utils::dir_ensure(path); |
||||
|
} |
||||
|
|
||||
|
vector<string> dir_list_all(const std::string &path, const bool incl_dot_and_dotdot) |
||||
|
{ |
||||
|
vector<string> ret; |
||||
|
if (!path_exists(path)) { |
||||
|
runtime_error e{ "dir_list_all(\"" + path + "\") - Error: does not exist" }; |
||||
|
throw(e); |
||||
|
} |
||||
|
|
||||
|
if (!path_is_dir(path)) { |
||||
|
runtime_error e{ "dir_list_all(\"" + path + "\") - Error: is not a directory" }; |
||||
|
throw(e); |
||||
|
} |
||||
|
|
||||
|
DIR *dirp = opendir(path.c_str()); |
||||
|
if (dirp == nullptr) { |
||||
|
runtime_error e{ "dir_list_all(\"" + path + "\") - Error opening dir" }; |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
struct dirent *dp; |
||||
|
while ((dp = readdir(dirp)) != NULL) { |
||||
|
ret.push_back(string(dp->d_name)); |
||||
|
} |
||||
|
|
||||
|
if (!incl_dot_and_dotdot) { |
||||
|
ret.erase( |
||||
|
remove_if( |
||||
|
ret.begin(), |
||||
|
ret.end(), |
||||
|
[](string elem) { return (elem == "." || elem == ".."); }), |
||||
|
ret.end()); |
||||
|
} |
||||
|
|
||||
|
closedir(dirp); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
vector<string> dir_list_dirs(const string &dirname, const bool incl_dot_and_dotdot) |
||||
|
{ |
||||
|
vector<string> ret = dir_list_all(dirname, incl_dot_and_dotdot); |
||||
|
ret.erase( |
||||
|
remove_if( |
||||
|
ret.begin(), |
||||
|
ret.end(), |
||||
|
[dirname](string elem) { return !path_is_dir(dirname + "/" + elem); }), |
||||
|
ret.end()); |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
vector<string> dir_list_files(const string &dirname) |
||||
|
{ |
||||
|
vector<string> ret = dir_list_all(dirname); |
||||
|
ret.erase( |
||||
|
remove_if( |
||||
|
ret.begin(), |
||||
|
ret.end(), |
||||
|
[dirname](string elem) { return path_is_dir(dirname + "/" + elem); }), |
||||
|
ret.end()); |
||||
|
return ret; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
// Attention, it pads left...
|
||||
|
string padTo(const string &str, const size_t num, const char paddingChar) |
||||
|
{ |
||||
|
string ret{ str }; |
||||
|
if (num > ret.size()) { |
||||
|
ret.insert(0, num - ret.size(), paddingChar); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string clip(const std::string &str, const size_t len) |
||||
|
{ |
||||
|
std::string ret{ str }; |
||||
|
if (str.length() > len) { |
||||
|
ret = str.substr(0, len) + "..."; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// prints the beginning and the end of the string and clips out
|
||||
|
// content in the middle replaced by "... tldr ..."
|
||||
|
std::string tldr(const std::string &str, const size_t len) |
||||
|
{ |
||||
|
std::string decoration = "..."; |
||||
|
int trunclen = len - decoration.length(); |
||||
|
|
||||
|
std::string ret{ str }; |
||||
|
if (str.length() > len) { |
||||
|
ret = "\n" + str.substr(0, (int)floor(trunclen / 2.0)) + "\n... tldr ...\n"; |
||||
|
ret += str.substr(str.length() - (int)floor(trunclen / 2.0), str.length()); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
string to_termcol(const Color &col) |
||||
|
{ |
||||
|
switch (col) { |
||||
|
case Color::RESET: |
||||
|
return "\033[0m"; |
||||
|
case Color::BLACK: |
||||
|
return "\033[30m"; |
||||
|
case Color::RED: |
||||
|
return "\033[31m"; |
||||
|
case Color::GREEN: |
||||
|
return "\033[32m"; |
||||
|
case Color::YELLOW: |
||||
|
return "\033[33m"; |
||||
|
case Color::BLUE: |
||||
|
return "\033[34m"; |
||||
|
case Color::MAGENTA: |
||||
|
return "\033[35m"; |
||||
|
case Color::CYAN: |
||||
|
return "\033[36m"; |
||||
|
case Color::WHITE: |
||||
|
return "\033[37m"; |
||||
|
default: |
||||
|
return "\033[0m"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void sleep_millis(int milis) |
||||
|
{ |
||||
|
std::chrono::milliseconds timespan(milis); |
||||
|
std::this_thread::sleep_for(timespan); |
||||
|
} |
||||
|
|
||||
|
unsigned char random_char(unsigned char min, unsigned char max) |
||||
|
{ |
||||
|
std::random_device rd; |
||||
|
std::mt19937 gen(rd()); |
||||
|
std::uniform_int_distribution<short> dis(static_cast<short>(min), static_cast<short>(max)); |
||||
|
return static_cast<unsigned char>(dis(gen)); |
||||
|
} |
||||
|
|
||||
|
std::string random_string(unsigned char min, unsigned char max, int len) |
||||
|
{ |
||||
|
std::stringstream ret; |
||||
|
for (int i = 0; i < len; i++) { |
||||
|
ret << random_char(97, 122); |
||||
|
} |
||||
|
return ret.str(); |
||||
|
} |
||||
|
|
||||
|
} // namespace Utils
|
||||
|
} // namespace pEp
|
@ -0,0 +1,94 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_STD_UTILS_HH |
||||
|
#define LIBPEPADAPTER_STD_UTILS_HH |
||||
|
|
||||
|
#include <string> |
||||
|
#include <exception> |
||||
|
#include <vector> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Utils { |
||||
|
// C-types helpers
|
||||
|
bool is_c_str_empty(const char *str); |
||||
|
|
||||
|
// C++/STL data types to string
|
||||
|
template<typename T> |
||||
|
std::string to_string(const std::vector<T> &v); |
||||
|
|
||||
|
// exception utils
|
||||
|
std::string nested_exception_to_string( |
||||
|
const std::exception &e, |
||||
|
int level = 0, |
||||
|
std::string src = ""); |
||||
|
void print_exception(const std::exception &e, int level = 0); |
||||
|
|
||||
|
// File utils
|
||||
|
// ----------
|
||||
|
// path (file & dir)
|
||||
|
bool path_exists(const std::string &filename); |
||||
|
void path_delete(const std::string &filename); |
||||
|
bool path_is_dir(const std::string &path); |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
void path_delete_all(const std::string &path); |
||||
|
#endif |
||||
|
|
||||
|
void path_ensure_not_existing(const std::string &path); |
||||
|
|
||||
|
// file
|
||||
|
std::ofstream file_create(const std::string &filename); |
||||
|
std::string file_read(const std::string &filename); |
||||
|
|
||||
|
// dir
|
||||
|
#ifndef WIN32 |
||||
|
void dir_create(const std::string &dirname, const mode_t mode = 0775); |
||||
|
void dir_ensure(const std::string &path); |
||||
|
void dir_recreate(const std::string &path); |
||||
|
|
||||
|
std::vector<std::string> dir_list_all( |
||||
|
const std::string &path, |
||||
|
const bool incl_dot_and_dotdot = false); |
||||
|
|
||||
|
std::vector<std::string> dir_list_dirs( |
||||
|
const std::string &dirname, |
||||
|
const bool incl_dot_and_dotdot = false); |
||||
|
|
||||
|
std::vector<std::string> dir_list_files(const std::string &dirname); |
||||
|
#endif |
||||
|
|
||||
|
//String formatting
|
||||
|
std::string padTo(const std::string &str, const size_t num, const char paddingChar); |
||||
|
std::string clip(const std::string &str, const size_t len); |
||||
|
std::string tldr(const std::string &str, const size_t len); |
||||
|
|
||||
|
enum class Color |
||||
|
{ |
||||
|
RESET, |
||||
|
BLACK, |
||||
|
RED, |
||||
|
GREEN, |
||||
|
YELLOW, |
||||
|
BLUE, |
||||
|
MAGENTA, |
||||
|
CYAN, |
||||
|
WHITE, |
||||
|
}; |
||||
|
|
||||
|
std::string to_termcol(const Color &col); |
||||
|
|
||||
|
|
||||
|
// Time
|
||||
|
void sleep_millis(int milis); |
||||
|
|
||||
|
// Random
|
||||
|
unsigned char random_char(unsigned char min, unsigned char max); |
||||
|
std::string random_string(unsigned char min, unsigned char max, int len); |
||||
|
|
||||
|
} // namespace Utils
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#include "std_utils.hxx" |
||||
|
|
||||
|
#endif // LIBPEPADAPTER_STD_UTILS_HH
|
@ -0,0 +1,22 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_STD_UTILS_HXX |
||||
|
#define LIBPEPADAPTER_STD_UTILS_HXX |
||||
|
|
||||
|
#include <sstream> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Utils { |
||||
|
template<typename T> |
||||
|
std::string to_string(const std::vector<T>& v) |
||||
|
{ |
||||
|
std::stringstream ss; |
||||
|
for (const T& elem : v) { |
||||
|
ss << elem << std::endl; |
||||
|
} |
||||
|
return ss.str(); |
||||
|
} |
||||
|
} // namespace Utils
|
||||
|
} // namespace pEp
|
||||
|
#endif // LIBPEPADAPTER_STD_UTILS_HXX
|
@ -0,0 +1,259 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "utils.hh" |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <iostream> |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Utils { |
||||
|
std::vector<::pEp_identity *> to_cxx(const ::identity_list &idl) |
||||
|
{ |
||||
|
vector<pEp_identity *> ret{}; |
||||
|
for (const ::identity_list *curr = &idl; curr != nullptr; curr = curr->next) { |
||||
|
if (curr->ident) { |
||||
|
ret.push_back(curr->ident); |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
string to_string(const ::pEp_identity *const ident, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (ident != nullptr) { |
||||
|
if (full) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "{" << endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "address: '" |
||||
|
<< (ident->address != nullptr ? ident->address : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "user_id: '" |
||||
|
<< (ident->user_id != nullptr ? ident->user_id : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "username: '" |
||||
|
<< (ident->username != nullptr ? ident->username : "NULL") << "'" |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') << "fpr: '" |
||||
|
<< (ident->fpr != nullptr ? ident->fpr : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "comm_type: " << ident->comm_type << endl; |
||||
|
builder << std::string(indent, '\t') << "lang: '" |
||||
|
<< static_cast<string>(ident->lang) << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "me: " << ident->me << endl; |
||||
|
builder << std::string(indent, '\t') << "major_ver: " << ident->major_ver << endl; |
||||
|
builder << std::string(indent, '\t') << "minor_ver: " << ident->minor_ver << endl; |
||||
|
builder << std::string(indent, '\t') << "enc_format: " << ident->enc_format |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') << "flags: " << ident->flags << endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
} else { |
||||
|
builder << std::string(indent, '\t') << "{ '" |
||||
|
<< (ident->address != nullptr ? ident->address : "NULL") << "' / '" |
||||
|
<< (ident->user_id != nullptr ? ident->user_id : "NULL") << "' / '" |
||||
|
<< (ident->username != nullptr ? ident->username : "NULL") << "' / '" |
||||
|
<< (ident->fpr != nullptr ? ident->fpr : "NULL") << "' }"; |
||||
|
} |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::bloblist_t *const blob, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (blob != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "[" << endl; |
||||
|
indent++; |
||||
|
for (const ::bloblist_t *curr = blob; curr != nullptr; curr = curr->next) { |
||||
|
if (full) { |
||||
|
builder << std::string(indent, '\t') << "{" << endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "mime_type: '" |
||||
|
<< (curr->mime_type != nullptr ? std::string(curr->mime_type) : "NULL") |
||||
|
<< "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "filename: '" |
||||
|
<< (curr->filename != nullptr ? curr->filename : "NULL") << "'" |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') << "size: " << curr->size << endl; |
||||
|
builder << std::string(indent, '\t') << "value: '" |
||||
|
<< (curr->value != nullptr |
||||
|
? Utils::tldr(std::string(curr->value), 300) |
||||
|
: "NULL") |
||||
|
<< "'" << endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}" << endl; |
||||
|
} else { |
||||
|
builder << std::string(indent, '\t'); |
||||
|
builder << "{ '" |
||||
|
<< (curr->mime_type != nullptr ? std::string(curr->mime_type) |
||||
|
: "NULL"); |
||||
|
builder << "' / '" << (curr->filename != nullptr ? curr->filename : "NULL"); |
||||
|
builder << "' / '" << curr->size << "'"; |
||||
|
builder << " }" << endl; |
||||
|
} |
||||
|
} |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "]" << endl; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::stringpair_list_t *const spl, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (spl != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "[" << endl; |
||||
|
indent++; |
||||
|
for (const ::stringpair_list_t *curr = spl; curr != nullptr; curr = curr->next) { |
||||
|
builder << std::string(indent, '\t') << "{ '"; |
||||
|
if (curr->value != nullptr) { |
||||
|
builder << (curr->value->key ? curr->value->key : "NULL"); |
||||
|
builder << "' : '"; |
||||
|
builder << (curr->value->value ? curr->value->value : "NULL"); |
||||
|
} |
||||
|
builder << "' }" << endl; |
||||
|
} |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "]" << endl; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::message *const msg, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (msg != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "{" << endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "from: " |
||||
|
<< (msg->from != nullptr ? to_string(msg->from, full, indent) : "NULL") |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') << "to: " |
||||
|
<< (msg->to != nullptr ? to_string(msg->to, full, indent) : "NULL") << endl; |
||||
|
builder << std::string(indent, '\t') << "shortmsg: '" |
||||
|
<< (msg->shortmsg != nullptr ? msg->shortmsg : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "longmsg: '" |
||||
|
<< (msg->longmsg != nullptr ? msg->longmsg : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "enc_format: " << msg->enc_format << endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "dir: " << (msg->dir == 0 ? "incomming" : "outgoing") << endl; |
||||
|
builder << std::string(indent, '\t') << "id: '" |
||||
|
<< (msg->id != nullptr ? msg->id : "NULL") << "'" << endl; |
||||
|
builder << std::string(indent, '\t') << "opt_fields: " |
||||
|
<< (msg->opt_fields ? to_string(msg->opt_fields, full, indent) : "NULL") |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') << "attachments: " |
||||
|
<< (msg->attachments ? to_string(msg->attachments, full, indent) : "NULL") |
||||
|
<< endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}" << endl; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::identity_list *const idl, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (idl != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "[" << endl; |
||||
|
indent++; |
||||
|
for (const ::identity_list *curr = idl; curr != nullptr; curr = curr->next) { |
||||
|
builder << to_string(curr->ident, full, indent) << endl; |
||||
|
} |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "]"; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
string to_string(const ::pEp_member *const member, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (member != nullptr) { |
||||
|
builder << std::string(indent, '\t') << "{" << endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "ident: " << to_string(member->ident, full, indent) << endl; |
||||
|
builder << std::string(indent, '\t') << "joined: " << member->joined << endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
string to_string(const ::member_list *const mbl, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (mbl != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "[" << endl; |
||||
|
indent++; |
||||
|
for (const member_list *curr = mbl; curr != nullptr; curr = curr->next) { |
||||
|
builder << to_string(curr->member, full, indent) << endl; |
||||
|
} |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "]"; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
string to_string(const ::pEp_group *const group, bool full, int indent) |
||||
|
{ |
||||
|
stringstream builder; |
||||
|
if (group != nullptr) { |
||||
|
builder << endl; |
||||
|
builder << std::string(indent, '\t') << "{" << endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "group_identity: " << to_string(group->group_identity, full, indent) |
||||
|
<< endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "manager: " << to_string(group->manager, full, indent) << endl; |
||||
|
builder << std::string(indent, '\t') << "active: " << group->active << endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "members: " << to_string(group->members, full, indent) << endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "]"; |
||||
|
} else { |
||||
|
builder << "NULL"; |
||||
|
} |
||||
|
|
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
// TODO: Move to std_utils
|
||||
|
std::string readKey() |
||||
|
{ |
||||
|
std::string ret; |
||||
|
std::cin >> ret; |
||||
|
return ret; |
||||
|
} |
||||
|
} // namespace Utils
|
||||
|
} // namespace pEp
|
@ -0,0 +1,35 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_UTILS_HH |
||||
|
#define LIBPEPADAPTER_UTILS_HH |
||||
|
|
||||
|
#include "pEpLog.hh" |
||||
|
#include <pEp/message.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/group.h> |
||||
|
#include <exception> |
||||
|
#include <vector> |
||||
|
#include <string> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Utils { |
||||
|
// C-types to C++ types
|
||||
|
std::vector<::pEp_identity *> to_cxx(const ::identity_list &idl); |
||||
|
|
||||
|
// pEpEngine datatypes to string
|
||||
|
std::string to_string(const ::pEp_identity *const ident, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::bloblist_t *const ident, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::stringpair_list_t *const spl, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::message *const msg, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::identity_list *const idl, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::pEp_member *const member, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::member_list *const mbl, bool full = true, int indent = 0); |
||||
|
std::string to_string(const ::pEp_group *const group, bool full = true, int indent = 0); |
||||
|
|
||||
|
// Misc
|
||||
|
std::string readKey(); // TODO: Move to std_utils
|
||||
|
|
||||
|
} // namespace Utils
|
||||
|
} // namespace pEp
|
||||
|
#endif // LIBPEPADAPTER_UTILS_HH
|
@ -1,165 +1,270 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "utils.hh" |
#include "utils.hh" |
||||
|
|
||||
#include <iostream> |
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
#include <pEp/identity_list.h> |
#include <pEp/identity_list.h> |
||||
|
#include <pEp/Adapter.hh> |
||||
#include "../../src/Adapter.hh" |
#include <pEp/status_to_string.hh> |
||||
#include "../../src/adapter_group.h" |
#include <pEp/mime.h> |
||||
|
#include <tuple> |
||||
using namespace std; |
|
||||
using namespace pEp; |
|
||||
|
|
||||
namespace pEp { |
namespace pEp { |
||||
namespace Test { |
namespace Test { |
||||
namespace Log { |
namespace Utils { |
||||
void logH1(string msg) |
|
||||
|
//Ident
|
||||
|
pEpIdent wrap(::pEp_identity *const ident) |
||||
{ |
{ |
||||
char decoration{ '=' }; |
assert(ident); |
||||
cout << endl |
auto ret = pEpIdent(ident, [](::pEp_identity *) {}); |
||||
<< endl |
return ret; |
||||
<< std::string(30, decoration) << ' ' << msg << ' ' |
|
||||
<< std::string(30, decoration) << endl; |
|
||||
} |
} |
||||
|
|
||||
void logH2(string msg) |
pEpIdent appropriate(::pEp_identity *const ident) |
||||
{ |
{ |
||||
char decoration{ '-' }; |
assert(ident); |
||||
cout << endl |
auto ret = pEpIdent(ident, ::free_identity); |
||||
<< std::string(10, decoration) << ' ' << msg << ' ' |
return ret; |
||||
<< std::string(10, decoration) << endl; |
|
||||
} |
} |
||||
} // namespace Log
|
|
||||
|
|
||||
namespace Utils { |
pEpIdent dup(const ::pEp_identity *const ident) |
||||
string identity_to_string(::pEp_identity* ident, bool full, int indent) |
{ |
||||
{ |
assert(ident); |
||||
|
auto ret = pEpIdent(::identity_dup(ident), ::free_identity); |
||||
stringstream builder; |
return ret; |
||||
if (ident != nullptr) { |
} |
||||
if (full) { |
|
||||
builder << endl; |
|
||||
builder << std::string(indent, '\t') << "{" << endl; |
|
||||
indent++; |
|
||||
builder << std::string(indent, '\t') << "address: " |
|
||||
<< (ident->address != nullptr ? ident->address : "NULL") << endl; |
|
||||
builder << std::string(indent, '\t') << "user_id: " |
|
||||
<< (ident->user_id != nullptr ? ident->user_id : "NULL") << endl; |
|
||||
builder << std::string(indent, '\t') << "username: " |
|
||||
<< (ident->username != nullptr ? ident->username : "NULL") << endl; |
|
||||
builder << std::string(indent, '\t') |
|
||||
<< "fpr: " << (ident->fpr != nullptr ? ident->fpr : "NULL") << endl; |
|
||||
builder << std::string(indent, '\t') << "comm_type: " << ident->comm_type |
|
||||
<< endl; |
|
||||
builder << std::string(indent, '\t') |
|
||||
<< "lang: " << static_cast<string>(ident->lang) << endl; |
|
||||
builder << std::string(indent, '\t') << "me: " << ident->me << endl; |
|
||||
builder << std::string(indent, '\t') << "major_ver: " << ident->major_ver |
|
||||
<< endl; |
|
||||
builder << std::string(indent, '\t') << "minor_ver: " << ident->minor_ver |
|
||||
<< endl; |
|
||||
builder << std::string(indent, '\t') << "enc_format: " << ident->enc_format |
|
||||
<< endl; |
|
||||
builder << std::string(indent, '\t') << "flags: " << ident->flags << endl; |
|
||||
indent--; |
|
||||
builder << std::string(indent, '\t') << "}"; |
|
||||
} else { |
|
||||
builder << "{ " << (ident->address != nullptr ? ident->address : "NULL") |
|
||||
<< "/" << (ident->user_id != nullptr ? ident->user_id : "NULL") |
|
||||
<< "/" << (ident->username != nullptr ? ident->username : "NULL") |
|
||||
<< "/" << (ident->fpr != nullptr ? ident->fpr : "NULL") << " }"; |
|
||||
} |
|
||||
} else { |
|
||||
builder << "NULL"; |
|
||||
} |
|
||||
|
|
||||
return builder.str(); |
pEpIdent kill(::pEp_identity *const ident) |
||||
|
{ |
||||
|
assert(ident); |
||||
|
auto ret = pEpIdent(::identity_dup(ident), ::free_identity); |
||||
|
::free_identity(ident); |
||||
|
return ret; |
||||
} |
} |
||||
|
|
||||
std::string identitylist_to_string(::identity_list* idl, bool full, int indent) |
//IdentityList
|
||||
|
pEpIdentList wrap(::identity_list *const ident) |
||||
{ |
{ |
||||
stringstream builder; |
assert(ident); |
||||
if (idl != nullptr) { |
auto ret = pEpIdentList(ident, [](::identity_list *) {}); |
||||
builder << endl; |
return ret; |
||||
builder << std::string(indent, '\t') << "[" << endl; |
} |
||||
indent++; |
|
||||
for (::identity_list* curr = idl; curr != nullptr; curr = curr->next) { |
|
||||
builder << identity_to_string(curr->ident, full, indent) << endl; |
|
||||
} |
|
||||
indent--; |
|
||||
builder << std::string(indent, '\t') << "]"; |
|
||||
} else { |
|
||||
builder << "NULL"; |
|
||||
} |
|
||||
|
|
||||
return builder.str(); |
pEpIdentList appropriate(::identity_list *const ident) |
||||
|
{ |
||||
|
assert(ident); |
||||
|
auto ret = pEpIdentList(ident, ::free_identity_list); |
||||
|
return ret; |
||||
} |
} |
||||
|
|
||||
string member_to_string(::pEp_member* member, bool full, int indent) |
pEpIdentList dup(const ::identity_list *const ident) |
||||
{ |
{ |
||||
stringstream builder; |
assert(ident); |
||||
if (member != nullptr) { |
auto ret = pEpIdentList(::identity_list_dup(ident), ::free_identity_list); |
||||
builder << std::string(indent, '\t') << "{" << endl; |
return ret; |
||||
indent++; |
} |
||||
builder << std::string(indent, '\t') |
|
||||
<< "ident: " << identity_to_string(member->ident, full, indent) << endl; |
pEpIdentList kill(::identity_list *const ident) |
||||
builder << std::string(indent, '\t') << "joined: " << member->joined << endl; |
{ |
||||
indent--; |
assert(ident); |
||||
builder << std::string(indent, '\t') << "}"; |
auto ret = pEpIdentList(::identity_list_dup(ident), ::free_identity_list); |
||||
} else { |
::free_identity_list(ident); |
||||
builder << "NULL"; |
return ret; |
||||
|
} |
||||
|
|
||||
|
//Message
|
||||
|
pEpMessage wrap(::message *const msg) |
||||
|
{ |
||||
|
assert(msg); |
||||
|
auto ret = pEpMessage(msg, [](::message *) {}); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
pEpMessage appropriate(::message *const msg) |
||||
|
{ |
||||
|
assert(msg); |
||||
|
auto ret = pEpMessage(msg, ::free_message); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
pEpMessage dup(const ::message *const msg) |
||||
|
{ |
||||
|
assert(msg); |
||||
|
auto ret = pEpMessage(::message_dup(msg), ::free_message); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
pEpMessage kill(::message *const msg) |
||||
|
{ |
||||
|
assert(msg); |
||||
|
auto ret = pEpMessage(::message_dup(msg), ::free_message); |
||||
|
::free_message(msg); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// helpers
|
||||
|
pEpIdent createOwnIdent(const std::string &address) |
||||
|
{ |
||||
|
std::string name; |
||||
|
::pEp_identity *ident = nullptr; |
||||
|
ident = ::new_identity( |
||||
|
strdup(address.c_str()), |
||||
|
"", |
||||
|
PEP_OWN_USERID, |
||||
|
("myself " + address).c_str()); |
||||
|
ident->me = true; |
||||
|
|
||||
|
return appropriate(ident); |
||||
|
} |
||||
|
|
||||
|
pEpIdent createCptIdent(const std::string &address) |
||||
|
{ |
||||
|
std::string name; |
||||
|
::pEp_identity *ident = nullptr; |
||||
|
ident = ::new_identity( |
||||
|
strdup(address.c_str()), |
||||
|
"", |
||||
|
"", |
||||
|
("partner " + address).c_str()); |
||||
|
ident->me = false; |
||||
|
|
||||
|
return appropriate(ident); |
||||
|
} |
||||
|
|
||||
|
pEpIdent createRawIdent(const std::string &address) |
||||
|
{ |
||||
|
std::string name; |
||||
|
::pEp_identity *ident = nullptr; |
||||
|
ident = ::new_identity(strdup(address.c_str()), "", "", ""); |
||||
|
ident->me = false; |
||||
|
|
||||
|
return appropriate(ident); |
||||
|
} |
||||
|
|
||||
|
pEpIdentList createIdentityList(const std::vector<std::string> &addresses) |
||||
|
{ |
||||
|
::identity_list *list; |
||||
|
list = ::new_identity_list(nullptr); |
||||
|
for (std::string addr : addresses) { |
||||
|
::identity_list_add(list, ::identity_dup(createCptIdent(addr).get())); |
||||
} |
} |
||||
|
return appropriate(list); |
||||
|
} |
||||
|
|
||||
|
pEpMessage createMessage(pEpIdent from, pEpIdent to, const std::string &longmsg) |
||||
|
{ |
||||
|
// create and fill in msg
|
||||
|
::message *msg = ::new_message(PEP_dir_outgoing); |
||||
|
msg->from = ::identity_dup(from.get()); |
||||
|
msg->to = ::new_identity_list(::identity_dup(to.get())); |
||||
|
msg->longmsg = strdup(longmsg.c_str()); |
||||
|
|
||||
return builder.str(); |
pEpMessage ret = appropriate(msg); |
||||
|
return ret; |
||||
} |
} |
||||
|
|
||||
string memberlist_to_string(::member_list* mbl, bool full, int indent) |
pEpMessage createMessage(pEpIdent from, const std::string &to_addr, const std::string &longmsg) |
||||
{ |
{ |
||||
stringstream builder; |
pEpIdent to_ident = createCptIdent(to_addr); |
||||
if (mbl != nullptr) { |
return createMessage(from, to_ident, longmsg); |
||||
builder << endl; |
} |
||||
builder << std::string(indent, '\t') << "[" << endl; |
|
||||
indent++; |
std::string mimeEncode(const pEpMessage msg) |
||||
for (member_list* curr_member = mbl; curr_member != nullptr; |
{ |
||||
curr_member = curr_member->next) { |
char *mimetext; |
||||
builder << member_to_string(curr_member->member, full, indent) << endl; |
PEP_STATUS status = ::mime_encode_message(msg.get(), false, &mimetext, false); |
||||
} |
throw_status(status); |
||||
indent--; |
std::string text{ mimetext }; |
||||
builder << std::string(indent, '\t') << "]"; |
free(mimetext); |
||||
|
return text; |
||||
|
} |
||||
|
|
||||
|
pEpMessage mimeDecode(const std::string &mime_text) |
||||
|
{ |
||||
|
::message *msg; |
||||
|
bool has_possible_pEp_msg; |
||||
|
::PEP_STATUS status = ::mime_decode_message( |
||||
|
mime_text.c_str(), |
||||
|
mime_text.length(), |
||||
|
&msg, |
||||
|
&has_possible_pEp_msg); |
||||
|
throw_status(status); |
||||
|
return pEpMessage(msg, ::free_message); |
||||
|
} |
||||
|
|
||||
|
EncryptResult encryptMessage(const pEpMessage msg) |
||||
|
{ |
||||
|
pEpMessage msg_out; |
||||
|
bool could_encrypt = false; |
||||
|
::message *msgenc = nullptr; |
||||
|
PEP_STATUS status = ::encrypt_message( |
||||
|
Adapter::session(), |
||||
|
msg.get(), |
||||
|
nullptr, |
||||
|
&msgenc, |
||||
|
PEP_enc_PEP, |
||||
|
0); |
||||
|
throw_status(status); |
||||
|
::message *msg_out_p = nullptr; |
||||
|
if (msgenc != nullptr) { |
||||
|
could_encrypt = true; |
||||
|
msg_out = appropriate(msgenc); |
||||
} else { |
} else { |
||||
builder << "NULL"; |
could_encrypt = false; |
||||
|
msg_out = msg; |
||||
} |
} |
||||
|
return EncryptResult(msg_out, "", could_encrypt); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
DecryptResult decryptMessage(const pEpMessage msg, ::PEP_decrypt_flags_t *flags) |
||||
|
{ |
||||
|
pEpMessage msg_out; |
||||
|
bool was_encrypted = false; |
||||
|
|
||||
return builder.str(); |
::message *dec{ nullptr }; |
||||
} |
::stringlist_t *kl = ::new_stringlist(""); |
||||
|
::PEP_rating rating; |
||||
string group_to_string(::pEp_group* group, bool full, int indent) |
PEP_STATUS status = ::decrypt_message( |
||||
{ |
Adapter::session(), |
||||
stringstream builder; |
msg.get(), |
||||
if (group != nullptr) { |
&dec, |
||||
builder << endl; |
&kl, |
||||
builder << std::string(indent, '\t') << "{" << endl; |
&rating, |
||||
indent++; |
flags); |
||||
builder << std::string(indent, '\t') << "group_identity: " |
throw_status(status); |
||||
<< identity_to_string(group->group_identity, full, indent) << endl; |
if (dec != nullptr) { |
||||
builder << std::string(indent, '\t') |
was_encrypted = true; |
||||
<< "manager: " << identity_to_string(group->manager, full, indent) |
msg_out = appropriate(dec); |
||||
<< endl; |
|
||||
builder << std::string(indent, '\t') << "active: " << group->active << endl; |
|
||||
builder << std::string(indent, '\t') |
|
||||
<< "members: " << memberlist_to_string(group->members, full, indent) |
|
||||
<< endl; |
|
||||
indent--; |
|
||||
builder << std::string(indent, '\t') << "]"; |
|
||||
} else { |
} else { |
||||
builder << "NULL"; |
was_encrypted = false; |
||||
|
msg_out = msg; |
||||
} |
} |
||||
|
return DecryptResult(msg_out, rating, kl, flags, was_encrypted); |
||||
|
} |
||||
|
|
||||
|
DecryptResult decryptMessage(const pEpMessage msg) |
||||
|
{ |
||||
|
::PEP_decrypt_flags_t dummy{ 0 }; |
||||
|
return decryptMessage(msg, &dummy); |
||||
|
} |
||||
|
|
||||
return builder.str(); |
EncryptResult encryptAndEncode(const pEpMessage msg) |
||||
|
{ |
||||
|
EncryptResult ret = encryptMessage(msg); |
||||
|
std::string mime_text = mimeEncode(std::get<0>(ret)); |
||||
|
std::get<1>(ret) = mime_text; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
DecryptResult decryptAndDecode(const std::string &mime_data) |
||||
|
{ |
||||
|
DecryptResult ret; |
||||
|
pEpMessage rx_msg = mimeDecode(mime_data); |
||||
|
ret = decryptMessage(rx_msg); |
||||
|
return ret; |
||||
} |
} |
||||
} // namespace Utils
|
} // namespace Utils
|
||||
} // namespace Test
|
} // namespace Test
|
||||
} // namespace pEp
|
} // namespace pEp
|
@ -1,27 +1,132 @@ |
|||||
// This file is under GNU General Public License 3.0
|
// This file is under GNU General Public License 3.0
|
||||
// see LICENSE.txt
|
// see LICENSE.txt
|
||||
|
|
||||
#ifndef LIBPEPADAPTER_UTILS_HH |
#ifndef LIBPEPADAPTER_TEST_UTILS_HH |
||||
#define LIBPEPADAPTER_UTILS_HH |
#define LIBPEPADAPTER_TEST_UTILS_HH |
||||
|
|
||||
|
#include "../../src/pEpLog.hh" |
||||
#include <string> |
#include <string> |
||||
#include <pEp/message.h> |
#include <exception> |
||||
|
#include <chrono> |
||||
|
#include <thread> |
||||
|
#include <cstring> |
||||
|
#include <tuple> |
||||
|
#include <pEp/pEpEngine.h> |
||||
#include <pEp/identity_list.h> |
#include <pEp/identity_list.h> |
||||
#include <pEp/group.h> |
#include <pEp/message.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
#ifndef ASSERT_EXCEPT |
||||
|
#define ASSERT_EXCEPT(func) \ |
||||
|
do { \ |
||||
|
try { \ |
||||
|
(func); \ |
||||
|
assert(false); \ |
||||
|
} catch (const exception &e) { \ |
||||
|
pEp::Adapter::pEpLog::log(nested_exception_to_string(e)); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif |
||||
|
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
// Logging macros for testing
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
// Use the macros if you need the message to be prefixed with "thread - __FILE__::__FUNTION__"
|
||||
|
// OTHERWISE, just use the logging functions from pEp::Adapter::pEpLog
|
||||
|
|
||||
|
// TESTLOG - logformat "thread - __FILE__::__FUNTION__ - <message>"
|
||||
|
// To be used in a non-class/object context
|
||||
|
#ifndef TESTLOG |
||||
|
#define TESTLOG(msg) \ |
||||
|
do { \ |
||||
|
std::stringstream msg_; \ |
||||
|
msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \ |
||||
|
msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \ |
||||
|
msg_ << " - " << msg; \ |
||||
|
pEp::Adapter::pEpLog::log(msg_.str()); \ |
||||
|
} while (0) |
||||
|
#endif // TESTLOG
|
||||
|
|
||||
|
// TESTLOGH1 - logformat "Thread - __FILE__::__FUNTION__ - <=============== message ==============>"
|
||||
|
#ifndef TESTLOGH1 |
||||
|
#define TESTLOGH1(msg) \ |
||||
|
do { \ |
||||
|
std::stringstream msg_; \ |
||||
|
msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \ |
||||
|
msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \ |
||||
|
msg_ << " - " << pEp::Adapter::pEpLog::decorateH1(msg); \ |
||||
|
pEp::Adapter::pEpLog::log(msg_.str()); \ |
||||
|
} while (0) |
||||
|
#endif // TESTLOGH1
|
||||
|
|
||||
|
// TESTLOGH2 - logformat "Thread - __FILE__::__FUNTION__ - <--------------- message -------------->"
|
||||
|
#ifndef TESTLOGH2 |
||||
|
#define TESTLOGH2(msg) \ |
||||
|
do { \ |
||||
|
std::stringstream msg_; \ |
||||
|
msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \ |
||||
|
msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \ |
||||
|
msg_ << " - " << pEp::Adapter::pEpLog::decorateH2(msg); \ |
||||
|
pEp::Adapter::pEpLog::log(msg_.str()); \ |
||||
|
} while (0) |
||||
|
#endif // TESTLOGH2
|
||||
|
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
namespace pEp { |
namespace pEp { |
||||
namespace Test { |
namespace Test { |
||||
namespace Log { |
|
||||
void logH1(std::string msg); |
|
||||
void logH2(std::string msg); |
|
||||
} |
|
||||
namespace Utils { |
namespace Utils { |
||||
std::string identity_to_string(::pEp_identity* ident, bool full = true, int indent = 0); |
using pEpIdent = std::shared_ptr<::pEp_identity>; |
||||
std::string identitylist_to_string(::identity_list * idl, bool full = true, int indent = 0); |
using pEpIdentList = std::shared_ptr<::identity_list>; |
||||
std::string member_to_string(::pEp_member* member, bool full = true, int indent = 0); |
using pEpMessage = std::shared_ptr<::message>; |
||||
std::string memberlist_to_string(::member_list* mbl, bool full = true, int indent = 0); |
// [ DecryptedMessage, Rating, KeyList, Flags, WasEncrypted ]
|
||||
std::string group_to_string(::pEp_group* group, bool full = true, int indent = 0); |
using DecryptResult = std:: |
||||
} |
tuple<pEpMessage, ::PEP_rating, ::stringlist_t *, ::PEP_decrypt_flags_t *, bool>; |
||||
} // namespace Test
|
// [ EncryptedMessage, MimeText, couldEncrypt ]
|
||||
|
using EncryptResult = std::tuple<pEpMessage, std::string, bool>; |
||||
|
|
||||
|
// Datatypes
|
||||
|
//Ident
|
||||
|
pEpIdent wrap(::pEp_identity *const ident); |
||||
|
pEpIdent appropriate(::pEp_identity *const ident); |
||||
|
pEpIdent dup(const ::pEp_identity *const ident); |
||||
|
pEpIdent kill(::pEp_identity *const ident); |
||||
|
|
||||
|
//IdentityList
|
||||
|
pEpIdentList wrap(::identity_list *const ident); |
||||
|
pEpIdentList appropriate(::identity_list *const ident); |
||||
|
pEpIdentList dup(const ::identity_list *const ident); |
||||
|
pEpIdentList kill(::identity_list *const ident); |
||||
|
|
||||
|
//Message
|
||||
|
pEpMessage wrap(::message *const msg); |
||||
|
pEpMessage appropriate(::message *const msg); |
||||
|
pEpMessage dup(const ::message *const msg); |
||||
|
pEpMessage kill(::message *const msg); |
||||
|
|
||||
|
// helpers
|
||||
|
pEpIdent createOwnIdent(const std::string &address); |
||||
|
pEpIdent createCptIdent(const std::string &address); |
||||
|
pEpIdent createRawIdent(const std::string &address); |
||||
|
pEpIdentList createIdentityList(const std::vector<std::string> &addresses); |
||||
|
pEpMessage createMessage(pEpIdent from, pEpIdent to, const std::string &longmsg); |
||||
|
pEpMessage createMessage(pEpIdent from, const std::string &to_addr, const std::string &longmsg); |
||||
|
|
||||
|
|
||||
|
std::string mimeEncode(const pEpMessage msg); |
||||
|
pEpMessage mimeDecode(const std::string &mime_text); |
||||
|
|
||||
|
EncryptResult encryptMessage(const pEpMessage msg); |
||||
|
DecryptResult decryptMessage(const pEpMessage msg, ::PEP_decrypt_flags_t *flags); |
||||
|
DecryptResult decryptMessage(const pEpMessage msg); |
||||
|
|
||||
|
EncryptResult encryptAndEncode(const pEpMessage msg); |
||||
|
DecryptResult decryptAndDecode(const std::string &mime_data); |
||||
|
|
||||
|
} // namespace Utils
|
||||
|
} // namespace Test
|
||||
} // namespace pEp
|
} // namespace pEp
|
||||
#endif |
|
||||
|
#endif // LIBPEPADAPTER_TEST_UTILS_HH
|
@ -0,0 +1,39 @@ |
|||||
|
include ../../Makefile.conf |
||||
|
|
||||
|
TARGET=src/libPityTest.a |
||||
|
LDFLAGS:=-L../../src/ $(LDFLAGS) -L../framework/ |
||||
|
LDLIBS=-lstdc++ -lpEpAdapter -lpEpEngine |
||||
|
CXXFLAGS:=-std=c++11 -g -I./src $(CXXFLAGS) |
||||
|
TEST_EXTRA_OBJS=../framework/utils.o |
||||
|
|
||||
|
# Src
|
||||
|
SRC=$(wildcard src/*.cc) |
||||
|
OBJ=$(subst .cc,.o,$(SRC)) |
||||
|
|
||||
|
# Tests
|
||||
|
TEST_SRC=$(wildcard test/*.cc) |
||||
|
TEST_OBJ=$(subst .cc,,$(TEST_SRC)) |
||||
|
|
||||
|
|
||||
|
.PHONY: all clean rmtestdata |
||||
|
.DEFAULT_GOAL := all |
||||
|
|
||||
|
|
||||
|
all: $(TARGET) test |
||||
|
|
||||
|
$(TARGET): $(OBJ) $(TEST_EXTRA_OBJS) |
||||
|
$(AR) -rc $@ $^ |
||||
|
|
||||
|
|
||||
|
test : $(TEST_OBJ) |
||||
|
|
||||
|
$(TEST_OBJ): $(OBJ) $(TEST_EXTRA_OBJS) |
||||
|
|
||||
|
|
||||
|
clean: |
||||
|
rm -f $(TARGET) |
||||
|
rm -f $(OBJ) |
||||
|
rm -f $(TEST_OBJ) |
||||
|
rm -rf src/*.dSYM |
||||
|
rm -rf test/*.dSYM |
||||
|
|
@ -0,0 +1,456 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "AbstractPityUnit.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include <iostream> |
||||
|
#include <unistd.h> |
||||
|
#include <cstdlib> |
||||
|
#include <sys/stat.h> |
||||
|
#include <exception> |
||||
|
#include <memory> |
||||
|
#include <sys/wait.h> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
// static
|
||||
|
std::string AbstractPityUnit::_global_root_dir = "./pitytest_data/"; |
||||
|
// static
|
||||
|
bool AbstractPityUnit::debug_log_enabled = false; |
||||
|
// static
|
||||
|
int AbstractPityUnit::_procUnitsCount = 0; |
||||
|
|
||||
|
AbstractPityUnit::AbstractPityUnit(const std::string &name, ExecutionMode exec_mode) : |
||||
|
PityTree<AbstractPityUnit>(*this, name), _exec_mode{ exec_mode }, _procUnitNr{ 0 } |
||||
|
{ |
||||
|
_init(); |
||||
|
} |
||||
|
|
||||
|
AbstractPityUnit::AbstractPityUnit( |
||||
|
AbstractPityUnit &parent, |
||||
|
const std::string &name, |
||||
|
ExecutionMode exec_mode) : |
||||
|
PityTree<AbstractPityUnit>(*this, name, parent), |
||||
|
_exec_mode{ exec_mode }, _procUnitNr{ 0 } |
||||
|
{ |
||||
|
_init(); |
||||
|
} |
||||
|
|
||||
|
AbstractPityUnit::AbstractPityUnit(const AbstractPityUnit &rhs, AbstractPityUnit &self) : |
||||
|
PityTree<AbstractPityUnit>(rhs, self) |
||||
|
{ |
||||
|
_procUnitNr = rhs._procUnitNr; |
||||
|
_exec_mode = rhs._exec_mode; |
||||
|
_transport = rhs._transport; // Will re-initialized in run()
|
||||
|
_transport_endpoints = rhs._transport_endpoints; // Will re-initialized in run()
|
||||
|
_init(); |
||||
|
} |
||||
|
|
||||
|
AbstractPityUnit &AbstractPityUnit::operator=(const AbstractPityUnit &rhs) |
||||
|
{ |
||||
|
_procUnitNr = rhs._procUnitNr; |
||||
|
_exec_mode = rhs._exec_mode; |
||||
|
_transport = rhs._transport; |
||||
|
_transport_endpoints = rhs._transport_endpoints; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void AbstractPityUnit::_init() |
||||
|
{ |
||||
|
_log_mutex = std::make_shared<fs_mutex>("log.mutex"); |
||||
|
_log_mutex->release(); |
||||
|
} |
||||
|
|
||||
|
// static
|
||||
|
void AbstractPityUnit::setGlobalRootDir(const std::string &dir) |
||||
|
{ |
||||
|
AbstractPityUnit::_global_root_dir = dir; |
||||
|
} |
||||
|
|
||||
|
// static
|
||||
|
std::string AbstractPityUnit::getGlobalRootDir() |
||||
|
{ |
||||
|
return AbstractPityUnit::_global_root_dir; |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::setExecMode(AbstractPityUnit::ExecutionMode execMode) |
||||
|
{ |
||||
|
_exec_mode = execMode; |
||||
|
} |
||||
|
|
||||
|
// For:
|
||||
|
// RootUnit - "<name>"
|
||||
|
// ProcessUnit - ".../<proc>"
|
||||
|
// When Process as dir. parent - ".../<proc>/name"
|
||||
|
// When no process as dir. parent - ".../<proc>/.../name"
|
||||
|
std::string AbstractPityUnit::getPathShort() const |
||||
|
{ |
||||
|
std::string ret; |
||||
|
if (isRoot()) { |
||||
|
ret = getName(); |
||||
|
} else { |
||||
|
if (isProcessUnit()) { |
||||
|
ret += ".../" + getName(); |
||||
|
} else { |
||||
|
if (&(getParentProcessUnit()) == (getParent())) { |
||||
|
ret = getParentProcessUnit().getPathShort() + "/" + getName(); |
||||
|
} else { |
||||
|
ret = getParentProcessUnit().getPathShort() + "/.../" + getName(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// Every process has its own dir inside its rootUnitDir
|
||||
|
// All other units inherit processDir from their Root/ProcessUnit
|
||||
|
std::string AbstractPityUnit::getProcessDir() |
||||
|
{ |
||||
|
if (isRoot()) { |
||||
|
return getRootUnitDir(); |
||||
|
} else { |
||||
|
if (isProcessUnit()) { |
||||
|
return getGlobalRootDir() + _normalizeName(getPath()) + "/"; |
||||
|
} else { |
||||
|
return getParent()->getProcessDir(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Every RootUnit has its own dir
|
||||
|
std::string AbstractPityUnit::getRootUnitDir() |
||||
|
{ |
||||
|
return getGlobalRootDir() + getRoot().getName() + "/"; |
||||
|
} |
||||
|
|
||||
|
// Every process has its own dir inside its rootUnitDir
|
||||
|
// All other units inherit transportDir from their Root/ProcessUnit
|
||||
|
std::string AbstractPityUnit::getTransportDir() |
||||
|
{ |
||||
|
return getProcessDir() + "inbox/"; |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_initProcUnitNrRecurse() |
||||
|
{ |
||||
|
if (!isRoot()) { |
||||
|
// Inherit
|
||||
|
_procUnitNr = getParent()->_procUnitNr; |
||||
|
//Or update if procUnit
|
||||
|
if (isProcessUnit()) { |
||||
|
_procUnitsCount++; |
||||
|
_procUnitNr = _procUnitsCount; |
||||
|
} |
||||
|
} else { |
||||
|
_procUnitNr = _procUnitsCount; |
||||
|
} |
||||
|
|
||||
|
// Recurse
|
||||
|
for (const auto &chld : getChildRefs()) { |
||||
|
chld.second._initProcUnitNrRecurse(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_initTransportRecurse() |
||||
|
{ |
||||
|
|
||||
|
if (!isRoot()) { |
||||
|
if (isProcessUnit()) { |
||||
|
_createTransport(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Recurse
|
||||
|
for (const auto &chld : getChildRefs()) { |
||||
|
chld.second._initTransportRecurse(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_initDirsRecursive() |
||||
|
{ |
||||
|
Utils::dir_recreate(getProcessDir()); |
||||
|
|
||||
|
// Recurse
|
||||
|
for (const auto &child : getChildRefs()) { |
||||
|
child.second._initDirsRecursive(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void AbstractPityUnit::run(bool init_tree) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
|
||||
|
if (init_tree) { |
||||
|
logH1("PityTest Starting..."); |
||||
|
_logRaw("RootUnit: " + getPath()); |
||||
|
_logRaw("GlobalRootDir: " + getGlobalRootDir()); |
||||
|
|
||||
|
_logRaw("Ensuring GlobalRootDir..."); |
||||
|
Utils::dir_ensure(getGlobalRootDir()); |
||||
|
|
||||
|
_logRaw("Recreating process dirs recursively..."); |
||||
|
_initDirsRecursive(); |
||||
|
//TODO:HACK wait for dir
|
||||
|
Utils::sleep_millis(500); |
||||
|
|
||||
|
_logRaw("Initializing Transport recursively..."); |
||||
|
_initTransportRecurse(); |
||||
|
|
||||
|
_logRaw("\n\nTestTree"); |
||||
|
_logRaw("--------"); |
||||
|
_logRaw(to_string() + "\n"); |
||||
|
_procUnitsCount = 0; |
||||
|
_initProcUnitNrRecurse(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// TODO: hack
|
||||
|
setenv("HOME", getProcessDir().c_str(), true); |
||||
|
|
||||
|
// Execute in fork and wait here until process ends
|
||||
|
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork
|
||||
|
_executeInFork(std::bind(&AbstractPityUnit::_runRecurse, this), true); |
||||
|
// Execute in fork and go on, wait for process execution in the end
|
||||
|
} else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
||||
|
_executeInFork(std::bind(&AbstractPityUnit::_runRecurse, this), false); |
||||
|
// Execute as normal function
|
||||
|
} else if (_exec_mode == ExecutionMode::FUNCTION) { |
||||
|
_runRecurse(); |
||||
|
} else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { |
||||
|
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); |
||||
|
} else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) { |
||||
|
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); |
||||
|
} |
||||
|
|
||||
|
if (init_tree) { |
||||
|
_waitChildProcesses(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string AbstractPityUnit::to_string(bool recursive, int indent) |
||||
|
{ |
||||
|
std::string ret; |
||||
|
std::stringstream builder; |
||||
|
builder << std::string(indent * 4, ' '); |
||||
|
|
||||
|
builder << getName(); |
||||
|
builder << " [ "; |
||||
|
builder << to_string(_exec_mode) << " - "; |
||||
|
builder << "\"" << getProcessDir() << "\""; |
||||
|
builder << " ]"; |
||||
|
builder << std::endl; |
||||
|
ret = builder.str(); |
||||
|
|
||||
|
if (recursive) { |
||||
|
if (!getChildRefs().empty()) { |
||||
|
indent++; |
||||
|
for (const auto child : getChildRefs()) { |
||||
|
ret += child.second.to_string(true, indent); |
||||
|
} |
||||
|
indent--; |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string AbstractPityUnit::to_string(const ExecutionMode &emode) |
||||
|
{ |
||||
|
switch (emode) { |
||||
|
case ExecutionMode::FUNCTION: |
||||
|
return "FUNCTION"; |
||||
|
case ExecutionMode::PROCESS_SEQUENTIAL: |
||||
|
return "PROC_SEQ"; |
||||
|
case ExecutionMode::PROCESS_PARALLEL: |
||||
|
return "PROC_PAR"; |
||||
|
case ExecutionMode::THREAD_SEQUENTIAL: |
||||
|
return "THREAD_S"; |
||||
|
case ExecutionMode::THREAD_PARALLEL: |
||||
|
return "THREAD_P"; |
||||
|
case ExecutionMode::INHERIT: |
||||
|
return "INHERIT"; |
||||
|
default: |
||||
|
return "UNDEFINED EXECUTION MODE"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void AbstractPityUnit::registerAsTransportEndpoint() |
||||
|
{ |
||||
|
transportEndpoints().insert({ getName(), getTransportDir() }); |
||||
|
} |
||||
|
|
||||
|
Endpoints &AbstractPityUnit::transportEndpoints() |
||||
|
{ |
||||
|
if (isRoot()) { |
||||
|
return _transport_endpoints; |
||||
|
} else { |
||||
|
return getRoot().transportEndpoints(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::log(const std::string &msg) const |
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << "[ "; |
||||
|
builder << std::to_string(getpid()); |
||||
|
builder << " - "; |
||||
|
builder << getPathShort(); |
||||
|
builder << " ] - "; |
||||
|
builder << msg; |
||||
|
|
||||
|
_logRaw(builder.str()); |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::logH1(const std::string &msg) const |
||||
|
{ |
||||
|
Adapter::pEpLog::logH1(msg, _color()); |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::logH2(const std::string &msg) const |
||||
|
{ |
||||
|
Adapter::pEpLog::logH2(msg, _color()); |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::logH3(const std::string &msg) const |
||||
|
{ |
||||
|
Adapter::pEpLog::logH3(msg, _color()); |
||||
|
} |
||||
|
|
||||
|
// PRIVATE ---------------------------------------------------------------------------------
|
||||
|
void AbstractPityUnit::_runRecurse() |
||||
|
{ |
||||
|
logH2(_status_string("STARTING")); |
||||
|
_runSelf(); |
||||
|
if (!getChildRefs().empty()) { |
||||
|
for (const auto child : getChildRefs()) { |
||||
|
child.second.run(false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// This should be fine
|
||||
|
_waitChildProcesses(); |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_executeInFork(std::function<void(void)> func, bool wait_child) const |
||||
|
{ |
||||
|
pid_t pid; |
||||
|
pid = fork(); |
||||
|
if (pid == pid_t(0)) { |
||||
|
func(); |
||||
|
exit(0); |
||||
|
} else if (pid < pid_t(0)) { |
||||
|
throw std::runtime_error("Error forking"); |
||||
|
} |
||||
|
if (wait_child) { |
||||
|
_waitChildProcesses(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_waitChildProcesses() const |
||||
|
{ |
||||
|
int status; |
||||
|
pid_t pid; |
||||
|
while ((pid = wait(&status)) > 0) { |
||||
|
std::string color; |
||||
|
if (status == 0) { |
||||
|
color = "\033[1m\033[32m"; // Green
|
||||
|
} else { |
||||
|
color = "\033[1m\033[31m"; // Red
|
||||
|
} |
||||
|
logH3( |
||||
|
color + "PROCESS [ " + std::to_string((int)pid) + |
||||
|
" ] EXITED with status code: " + std::to_string(status) + |
||||
|
Utils::to_termcol(_color())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool AbstractPityUnit::isProcessUnit() const |
||||
|
{ |
||||
|
bool ret = false; |
||||
|
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL || |
||||
|
_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
||||
|
ret = true; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
const AbstractPityUnit &AbstractPityUnit::getParentProcessUnit() const |
||||
|
{ |
||||
|
if (isRoot() || isProcessUnit()) { |
||||
|
return *this; |
||||
|
} else { |
||||
|
return getParent()->getParentProcessUnit(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// Inherited (if null see parent recursively)
|
||||
|
void AbstractPityUnit::_createTransport() |
||||
|
{ |
||||
|
registerAsTransportEndpoint(); |
||||
|
_transport = std::make_shared<PityTransport>(getTransportDir(), transportEndpoints()); |
||||
|
} |
||||
|
|
||||
|
// Inherited (if null see parent recursively)
|
||||
|
PityTransport *AbstractPityUnit::transport() const |
||||
|
{ |
||||
|
// pEpLogClass("called");
|
||||
|
PityTransport *ret = nullptr; |
||||
|
|
||||
|
if (_transport != nullptr) { |
||||
|
ret = _transport.get(); |
||||
|
} else { |
||||
|
if (!isRoot()) { |
||||
|
ret = getParent()->transport(); |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::string AbstractPityUnit::_status_string(const std::string &msg) const |
||||
|
{ |
||||
|
std::string ret; |
||||
|
ret = "[ " + to_string(_exec_mode) + ": " + std::to_string(getpid()) + " ] [ " + |
||||
|
getPathShort() + " ] [ " + msg + " ]"; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
//static
|
||||
|
Utils::Color AbstractPityUnit::_colForProcUnitNr(int procUnitNr) |
||||
|
{ |
||||
|
int nrColors = 6; |
||||
|
switch (procUnitNr % nrColors) { |
||||
|
case 0: |
||||
|
return Utils::Color::WHITE; |
||||
|
case 1: |
||||
|
return Utils::Color::GREEN; |
||||
|
case 2: |
||||
|
return Utils::Color::YELLOW; |
||||
|
case 3: |
||||
|
return Utils::Color::CYAN; |
||||
|
case 4: |
||||
|
return Utils::Color::BLUE; |
||||
|
case 5: |
||||
|
return Utils::Color::MAGENTA; |
||||
|
default: |
||||
|
return Utils::Color::WHITE; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Utils::Color AbstractPityUnit::_color() const |
||||
|
{ |
||||
|
return _colForProcUnitNr(_procUnitNr); |
||||
|
} |
||||
|
|
||||
|
void AbstractPityUnit::_logRaw(const std::string &msg) const |
||||
|
{ |
||||
|
// fs-mutex to sync across processes
|
||||
|
_log_mutex->aquire(); |
||||
|
Adapter::pEpLog::log(msg, _color()); |
||||
|
_log_mutex->release(); |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,135 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_ABSTRACTPITYUNIT_HH |
||||
|
#define PITYTEST_ABSTRACTPITYUNIT_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include "fs_mutex.hh" |
||||
|
#include "PityTree.hh" |
||||
|
#include "PityTransport.hh" |
||||
|
#include <string> |
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
|
||||
|
// Yes, the mem mgmt is purely static on purpose (so far)
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
class AbstractPityUnit : public PityTree<AbstractPityUnit> { |
||||
|
public: |
||||
|
enum class ExecutionMode |
||||
|
{ |
||||
|
FUNCTION, |
||||
|
PROCESS_SEQUENTIAL, |
||||
|
PROCESS_PARALLEL, |
||||
|
THREAD_SEQUENTIAL, // unimplemented
|
||||
|
THREAD_PARALLEL, // unimplemented
|
||||
|
INHERIT |
||||
|
}; |
||||
|
|
||||
|
// Constructors
|
||||
|
// ------------
|
||||
|
// RootNode
|
||||
|
explicit AbstractPityUnit( |
||||
|
const std::string& name, |
||||
|
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
||||
|
|
||||
|
// LeafNode
|
||||
|
explicit AbstractPityUnit( |
||||
|
AbstractPityUnit& parent, |
||||
|
const std::string& name, |
||||
|
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
||||
|
|
||||
|
// Copy
|
||||
|
explicit AbstractPityUnit(const AbstractPityUnit& rhs, AbstractPityUnit& self); |
||||
|
|
||||
|
// copy-assign
|
||||
|
AbstractPityUnit& operator=(const AbstractPityUnit& rhs); |
||||
|
|
||||
|
AbstractPityUnit* clone() override = 0; |
||||
|
|
||||
|
// Read-Write
|
||||
|
static void setGlobalRootDir(const std::string& dir); |
||||
|
static std::string getGlobalRootDir(); |
||||
|
void setExecMode(ExecutionMode execMode); |
||||
|
|
||||
|
// Read-Only
|
||||
|
std::string getPathShort() const; |
||||
|
std::string getProcessDir(); // own process dir
|
||||
|
std::string getTransportDir(); |
||||
|
std::string getRootUnitDir(); |
||||
|
bool isProcessUnit() const; // true if it forks
|
||||
|
const AbstractPityUnit& getParentProcessUnit() const; |
||||
|
|
||||
|
|
||||
|
// Main funcs
|
||||
|
void run(bool init_tree = true); |
||||
|
|
||||
|
std::string to_string(bool recursive = true, int indent = 0); |
||||
|
static std::string to_string(const ExecutionMode& emode); |
||||
|
|
||||
|
// logging service
|
||||
|
void log(const std::string& msg) const; |
||||
|
void logH1(const std::string& msg) const; |
||||
|
void logH2(const std::string& msg) const; |
||||
|
void logH3(const std::string& msg) const; |
||||
|
|
||||
|
//Transport
|
||||
|
PityTransport* transport() const; |
||||
|
void registerAsTransportEndpoint(); |
||||
|
Endpoints& transportEndpoints(); |
||||
|
|
||||
|
// internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PityUnit", debug_log_enabled }; |
||||
|
|
||||
|
protected: |
||||
|
std::string _status_string(const std::string& msg) const; |
||||
|
static Utils::Color _colForProcUnitNr(int procUnitNr); |
||||
|
Utils::Color _color() const; |
||||
|
void _logRaw(const std::string& msg) const; |
||||
|
|
||||
|
// internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
|
||||
|
private: |
||||
|
// METHODS
|
||||
|
void _init(); |
||||
|
// Execution
|
||||
|
void _initProcUnitNrRecurse(); |
||||
|
void _initTransportRecurse(); |
||||
|
void _initDirsRecursive(); |
||||
|
void _runRecurse(); |
||||
|
virtual void _runSelf() = 0; |
||||
|
void _executeInFork(std::function<void(void)> func, bool wait_child) const; |
||||
|
void _waitChildProcesses() const; |
||||
|
|
||||
|
// Transport
|
||||
|
void _createTransport(); |
||||
|
|
||||
|
// Fields
|
||||
|
// ------
|
||||
|
static std::string _global_root_dir; |
||||
|
ExecutionMode _exec_mode; |
||||
|
int _procUnitNr; |
||||
|
static int _procUnitsCount; // will be increased in every constructor
|
||||
|
|
||||
|
// transport
|
||||
|
std::shared_ptr<PityTransport> _transport; //only ever read via transport()
|
||||
|
// TODO move endpoints into PityTransport
|
||||
|
Endpoints _transport_endpoints; // only ever access via transportEndpoints()
|
||||
|
|
||||
|
// fs-mutex to sync across processes
|
||||
|
std::shared_ptr<fs_mutex> _log_mutex = nullptr; |
||||
|
}; |
||||
|
|
||||
|
class PityAssertException : public std::runtime_error { |
||||
|
public: |
||||
|
PityAssertException(const std::string& string) : runtime_error(string) {} |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif |
@ -0,0 +1,32 @@ |
|||||
|
#include "PityModel.hh" |
||||
|
#include "PityNode.hh" |
||||
|
#include <random> |
||||
|
#include <memory> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
bool PityModel::debug_log_enabled = false; |
||||
|
|
||||
|
PityModel::PityModel(const std::string& name, int nodeCount) : _name{ name } |
||||
|
{ |
||||
|
for (int i = 0; i < nodeCount; i++) { |
||||
|
_nodes.emplace_back(std::make_shared<PityNode>(i)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string PityModel::getName() const |
||||
|
{ |
||||
|
return _name; |
||||
|
} |
||||
|
|
||||
|
std::vector<std::shared_ptr<PityNode>> PityModel::nodes() const |
||||
|
{ |
||||
|
return _nodes; |
||||
|
} |
||||
|
|
||||
|
PityNode* PityModel::nodeNr(int nr) const |
||||
|
{ |
||||
|
return nodes().at(nr).get(); |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,53 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYMODEL_HH |
||||
|
#define PITYTEST_PITYMODEL_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include "PityNode.hh" |
||||
|
#include <vector> |
||||
|
#include <memory> |
||||
|
|
||||
|
// The Model currently is as follows:
|
||||
|
// The Model creates the TestTree using PityUnits.
|
||||
|
// When creating the model you specify how many nodes you want
|
||||
|
//
|
||||
|
// ATTENTION - TODO:
|
||||
|
// Currently there is a strict 1-1 relationship of nodes and identities.
|
||||
|
// One Node has exactly one identity, and this identity is only on this node.
|
||||
|
// This needs to be enhanced to be a n-n relationship
|
||||
|
// The Transport only addresses nodes, not idents, therefore
|
||||
|
// If you have one ident on n nodes, the transport needs to check the model for all nodes the
|
||||
|
// ident is on and send the message to all these nodes.
|
||||
|
// If you have a node that has n identities, the persepective needs to specify node AND ident.
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
class PityModel { |
||||
|
public: |
||||
|
// Constructors
|
||||
|
PityModel() = delete; |
||||
|
PityModel(const std::string& name, int nodeCount); |
||||
|
|
||||
|
// Getters
|
||||
|
std::string getName() const; |
||||
|
std::vector<std::shared_ptr<PityNode>> nodes() const; |
||||
|
PityNode* nodeNr(int nr) const; |
||||
|
|
||||
|
//internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PityModel", debug_log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
std::vector<std::shared_ptr<PityNode>> _nodes; |
||||
|
std::string _name; |
||||
|
|
||||
|
//internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // PITYTEST_PITYMODEL_HH
|
@ -0,0 +1,63 @@ |
|||||
|
#include "PityNode.hh" |
||||
|
#include <memory> |
||||
|
#include <sstream> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
TestIdent::TestIdent(const std::string& addr) : |
||||
|
addr{ addr }, did_rx_encrypted{ false }, did_tx_encrypted{ false } |
||||
|
{ |
||||
|
ident = Test::Utils::createCptIdent(addr); |
||||
|
} |
||||
|
|
||||
|
TestIdent::TestIdent(const TestIdent& rhs) |
||||
|
{ |
||||
|
did_rx_encrypted = rhs.did_rx_encrypted; |
||||
|
did_tx_encrypted = rhs.did_tx_encrypted; |
||||
|
addr = rhs.addr; |
||||
|
ident = Test::Utils::dup(rhs.ident.get()); |
||||
|
} |
||||
|
|
||||
|
bool TestIdent::tofu_done() const |
||||
|
{ |
||||
|
return did_tx_encrypted && did_rx_encrypted; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// ---------------------------------------------------------------------------------
|
||||
|
|
||||
|
bool PityNode::debug_log_enabled = false; |
||||
|
|
||||
|
PityNode::PityNode(int nodeNr) : _node_nr{ nodeNr } |
||||
|
{ |
||||
|
logger_debug.set_instancename(getName()); |
||||
|
std::stringstream ss; |
||||
|
ss << this; |
||||
|
pEpLogClass(std::string("called with: " + std::to_string(_node_nr) + "AT: " + ss.str())); |
||||
|
ident = std::make_shared<TestIdent>(TestIdent(getName())); |
||||
|
} |
||||
|
|
||||
|
TestIdent& PityNode::getIdent() { |
||||
|
return *ident.get(); |
||||
|
} |
||||
|
|
||||
|
int PityNode::getNr() const |
||||
|
{ |
||||
|
return _node_nr; |
||||
|
} |
||||
|
|
||||
|
std::string PityNode::getName() const |
||||
|
{ |
||||
|
std::string ret; |
||||
|
ret += "node_" + std::to_string(_node_nr) + "@peptest.org"; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string PityNode::to_string() const |
||||
|
{ |
||||
|
std::string ret; |
||||
|
ret += "name: " + getName(); |
||||
|
return ret; |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,55 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYNODE_HH |
||||
|
#define PITYTEST_PITYNODE_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include "../../framework/utils.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
class TestIdent { |
||||
|
public: |
||||
|
TestIdent() = delete; |
||||
|
explicit TestIdent(const std::string& addr); |
||||
|
TestIdent(const TestIdent& rhs); |
||||
|
bool tofu_done() const; |
||||
|
|
||||
|
std::string addr; |
||||
|
pEp::Test::Utils::pEpIdent ident{}; |
||||
|
|
||||
|
// state
|
||||
|
bool did_tx_encrypted; |
||||
|
bool did_rx_encrypted; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class PityNode { |
||||
|
public: |
||||
|
// Constructors
|
||||
|
PityNode() = delete; |
||||
|
explicit PityNode(int nodeNr); |
||||
|
|
||||
|
// Getters
|
||||
|
TestIdent& getIdent(); |
||||
|
int getNr() const; |
||||
|
std::string getName() const; |
||||
|
std::string to_string() const; |
||||
|
|
||||
|
//internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PityNode", debug_log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
//fields
|
||||
|
const int _node_nr; |
||||
|
std::shared_ptr<TestIdent> ident; |
||||
|
|
||||
|
//internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // PITYTEST_PITYNODE_HH
|
@ -0,0 +1,48 @@ |
|||||
|
#include "PityPerspective.hh" |
||||
|
#include "PityModel.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
bool PityPerspective::debug_log_enabled = false; |
||||
|
|
||||
|
PityPerspective::PityPerspective(const PityModel& model) : model{ model }, peerNrAsCpt{ 0 } |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
} |
||||
|
|
||||
|
TestIdent* PityPerspective::getPeer(const std::string& addr) |
||||
|
{ |
||||
|
for (int i = 0; i < peers.size(); i++) { |
||||
|
if (peers.at(i).addr == addr) { |
||||
|
return &peers.at(i); |
||||
|
} |
||||
|
} |
||||
|
throw std::invalid_argument("getPeer(+" + addr + ") - not found"); |
||||
|
} |
||||
|
|
||||
|
void PityPerspective::setPeerNrAsCpt(int nr) |
||||
|
{ |
||||
|
if (nr < peers.size()) { |
||||
|
peerNrAsCpt = nr; |
||||
|
} else { |
||||
|
throw std::invalid_argument("setPeerNrAsCpt(" + std::to_string(nr) + ") - out of range"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
TestIdent& PityPerspective::getCpt() |
||||
|
{ |
||||
|
return peers.at(peerNrAsCpt); |
||||
|
} |
||||
|
|
||||
|
Group* PityPerspective::getGroup(const std::string& addr) |
||||
|
{ |
||||
|
for (int i = 0; i < groups.size(); i++) { |
||||
|
if (groups.at(i).addr == addr) { |
||||
|
return &groups.at(i); |
||||
|
} |
||||
|
} |
||||
|
throw std::invalid_argument("getGroup(" + addr + ") - not found"); |
||||
|
} |
||||
|
|
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,59 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYPERSPECTIVE_HH |
||||
|
#define PITYTEST_PITYPERSPECTIVE_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include "../../framework/utils.hh" |
||||
|
#include "PityModel.hh" |
||||
|
#include <map> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
|
||||
|
// Group
|
||||
|
struct Group { |
||||
|
std::string addr; |
||||
|
std::string moderator; |
||||
|
std::vector<TestIdent> members; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
class PityPerspective { |
||||
|
public: |
||||
|
// Constructors
|
||||
|
PityPerspective(const PityModel& model); |
||||
|
|
||||
|
// Lets grant access to the whole model too
|
||||
|
const PityModel& model; |
||||
|
|
||||
|
TestIdent* getPeer(const std::string& addr); |
||||
|
// Perspective
|
||||
|
std::string own_name; |
||||
|
// TestIdent* cpt = nullptr;
|
||||
|
void setPeerNrAsCpt(int nr); |
||||
|
TestIdent& getCpt(); |
||||
|
std::vector<TestIdent> peers; |
||||
|
|
||||
|
Test::Utils::pEpIdent own_ident; |
||||
|
// Test::Utils::pEpIdent cpt_ident;
|
||||
|
|
||||
|
// Groups
|
||||
|
Group* getGroup(const std::string& addr); |
||||
|
std::vector<Group> groups; |
||||
|
|
||||
|
//Callbacks
|
||||
|
//internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PityNode", debug_log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
int peerNrAsCpt; |
||||
|
//internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // PITYTEST_PITYPERSPECTIVE_HH
|
@ -0,0 +1,146 @@ |
|||||
|
#include "PitySwarm.hh" |
||||
|
#include "PityModel.hh" |
||||
|
#include "PityPerspective.hh" |
||||
|
#include "PityUnit.hh" |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <vector> |
||||
|
#include <functional> |
||||
|
#include <memory> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
bool PitySwarm::debug_log_enabled = false; |
||||
|
|
||||
|
PitySwarm::PitySwarm(const std::string& name, PityModel& model) : |
||||
|
_model{ model }, _swarmUnit{ name, |
||||
|
nullptr, |
||||
|
nullptr, |
||||
|
PityUnit<>::ExecutionMode::PROCESS_SEQUENTIAL } |
||||
|
{ |
||||
|
logger_debug.set_instancename(name); |
||||
|
pEpLogClass("called"); |
||||
|
|
||||
|
for (auto n : _model.nodes()) { |
||||
|
TestUnit* tmp = &_swarmUnit.addNew<TestUnit>( |
||||
|
n->getName(), |
||||
|
std::bind( |
||||
|
&PitySwarm::_init_process, |
||||
|
this, |
||||
|
std::placeholders::_1, |
||||
|
std::placeholders::_2), |
||||
|
nullptr, |
||||
|
TestUnit::ExecutionMode::PROCESS_PARALLEL); |
||||
|
// By value copies the context into the TestUnit
|
||||
|
tmp->setContext(_createPerspective(_model, n->getNr())); |
||||
|
_nodeUnits.insert(std::pair<int, TestUnit*>(n->getNr(), tmp)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
PitySwarm::PitySwarm(const PitySwarm& rhs, const std::string& new_name) : |
||||
|
_model{ rhs._model }, _swarmUnit{ new_name } |
||||
|
{ |
||||
|
logger_debug.set_instancename(new_name); |
||||
|
_swarmUnit = TestUnit(rhs._swarmUnit); |
||||
|
// TODO: Hack for some reason ExecMode is getting copied,
|
||||
|
// Copy of Swarm is _b0rken
|
||||
|
_swarmUnit.setExecMode(PityUnit<>::ExecutionMode::PROCESS_SEQUENTIAL); |
||||
|
_swarmUnit.setName(new_name); |
||||
|
for (auto n : rhs._nodeUnits) { |
||||
|
TestUnit* tmp = &_swarmUnit.addCopy(TestUnit(*n.second)); |
||||
|
_nodeUnits.insert(std::pair<int, TestUnit*>(n.first, tmp)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
PitySwarm::TestUnit& PitySwarm::getSwarmUnit() |
||||
|
{ |
||||
|
return _swarmUnit; |
||||
|
} |
||||
|
|
||||
|
PitySwarm::TestUnit& PitySwarm::getLeafUnit(int nodeNr) |
||||
|
{ |
||||
|
TestUnit* ret = nullptr; |
||||
|
TestUnit* current = _nodeUnits.at(nodeNr); |
||||
|
do { |
||||
|
if (current == nullptr) { |
||||
|
throw std::runtime_error("bad fatal cast in the ugly hack"); |
||||
|
} |
||||
|
if (current->getChildCount() == 0) { |
||||
|
ret = current; |
||||
|
} else { |
||||
|
current = dynamic_cast<TestUnit*>( |
||||
|
&(current->getChildRefs().begin()->second)); // random child
|
||||
|
} |
||||
|
} while (ret == nullptr); |
||||
|
return *ret; |
||||
|
} |
||||
|
|
||||
|
PitySwarm::TestUnit& PitySwarm::addTestUnit(int nodeNr, const TestUnit& unit) |
||||
|
{ |
||||
|
TestUnit& ret = getLeafUnit(nodeNr).addCopy(std::move(unit)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void PitySwarm::run() |
||||
|
{ |
||||
|
_swarmUnit.run(); |
||||
|
} |
||||
|
|
||||
|
// The perspective currently is completely defined by specifying a node,
|
||||
|
// since there is a 1-1 node/ident relationship currently
|
||||
|
PityPerspective PitySwarm::_createPerspective(const PityModel& model, int node_nr) |
||||
|
{ |
||||
|
PityPerspective psp{ model }; |
||||
|
psp.own_name = model.nodeNr(node_nr)->getName(); |
||||
|
|
||||
|
// Create peers, everyone but me
|
||||
|
for (int i = 0; i < model.nodes().size(); i++) { |
||||
|
if (i != node_nr) { |
||||
|
psp.peers.push_back(TestIdent(model.nodes().at(i)->getIdent())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Default partner is next node, its a circle
|
||||
|
// int partner_node_index = (node_nr + 1) % model.nodes().size();
|
||||
|
// psp.cpt_name = model.nodes().at(partner_node_index)->getName();
|
||||
|
|
||||
|
//Default partner is node 0
|
||||
|
if(model.nodes().size() > 1) { |
||||
|
if (node_nr == 0) { |
||||
|
psp.setPeerNrAsCpt(0); |
||||
|
} else { |
||||
|
for (int i = 0; i < psp.peers.size(); i++) { |
||||
|
if (psp.peers.at(i).addr == model.nodeNr(0)->getIdent().addr) { |
||||
|
psp.setPeerNrAsCpt(i); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Groups
|
||||
|
int grpOwneNode = 0; |
||||
|
Group grp1 = Group{}; |
||||
|
grp1.addr = "grp_" + model.nodeNr(grpOwneNode)->getName(); |
||||
|
grp1.moderator = model.nodeNr(grpOwneNode)->getName(); |
||||
|
// Create peers, everyone but me
|
||||
|
for (int i = 0; i < model.nodes().size(); i++) { |
||||
|
if (i != grpOwneNode) { |
||||
|
grp1.members.push_back(TestIdent(model.nodes().at(i)->getIdent())); |
||||
|
} |
||||
|
} |
||||
|
psp.groups.push_back(grp1); |
||||
|
|
||||
|
return psp; |
||||
|
} |
||||
|
|
||||
|
int PitySwarm::_init_process(TestUnit& unit, PityPerspective* ctx) |
||||
|
{ |
||||
|
// This should not be needed
|
||||
|
// std::cout << "Node _initProcUnitNrRecurse, setting $HOME" << std::endl;
|
||||
|
// std::string home = unit.processDir();
|
||||
|
// setenv("HOME", home.c_str(), true);
|
||||
|
return 0; |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,59 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYSWARM_HH |
||||
|
#define PITYTEST_PITYSWARM_HH |
||||
|
|
||||
|
#include "PityModel.hh" |
||||
|
#include "PityUnit.hh" |
||||
|
#include "PityPerspective.hh" |
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include <vector> |
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
|
||||
|
// PitySwarm creates a swarm of independent process nodes.
|
||||
|
// Each node has its own perspective
|
||||
|
// The perspective is a derivative of the model
|
||||
|
// The model is the objective reality
|
||||
|
// The perspective is the subjective reality
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
class PitySwarm { |
||||
|
public: |
||||
|
using TestUnit = PityUnit<PityPerspective>; |
||||
|
// Constructors
|
||||
|
explicit PitySwarm(const std::string& name, PityModel& model); |
||||
|
|
||||
|
PitySwarm(const PitySwarm& rhs, const std::string& new_name); |
||||
|
|
||||
|
TestUnit& addTestUnit(int nodeNr, const TestUnit& unit); |
||||
|
|
||||
|
TestUnit& getSwarmUnit(); |
||||
|
PitySwarm::TestUnit& getLeafUnit(int nodeNr); |
||||
|
void run(); |
||||
|
|
||||
|
|
||||
|
|
||||
|
//internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PitySwarm", debug_log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
// methods
|
||||
|
PityPerspective _createPerspective(const PityModel& model, int node_nr); |
||||
|
int _init_process(TestUnit& unit, PityPerspective* ctx); |
||||
|
|
||||
|
// fields
|
||||
|
PityModel& _model; |
||||
|
TestUnit _swarmUnit; |
||||
|
// each node has
|
||||
|
std::map<int, TestUnit*> _nodeUnits; |
||||
|
//internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // PITYTEST_PITYSWARM_HH
|
@ -0,0 +1,32 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYTEST_HH |
||||
|
#define PITYTEST_PITYTEST_HH |
||||
|
|
||||
|
#include "PityUnit.hh" |
||||
|
#include "PityModel.hh" |
||||
|
#include "PitySwarm.hh" |
||||
|
#include "PityPerspective.hh" |
||||
|
|
||||
|
#ifndef PITYASSERT |
||||
|
#define PITYASSERT(condition, msg) \ |
||||
|
do { \ |
||||
|
if (!(condition)) { \ |
||||
|
throw PityAssertException(msg); \ |
||||
|
} \ |
||||
|
} while (0); |
||||
|
#endif |
||||
|
|
||||
|
#define PITYASSERT_THROWS(func, msg) \ |
||||
|
do { \ |
||||
|
try { \ |
||||
|
(func); \ |
||||
|
PITYASSERT(false, msg); \ |
||||
|
} catch (const PityAssertException& pae) { \ |
||||
|
throw(pae); \ |
||||
|
} catch (const std::exception& e) { \ |
||||
|
} catch (...) { \ |
||||
|
} \ |
||||
|
} while (0); |
||||
|
#endif |
@ -0,0 +1,97 @@ |
|||||
|
#include "PityTransport.hh" |
||||
|
#include "PityUnit.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include "iostream" |
||||
|
#include <random> |
||||
|
#include <fstream> |
||||
|
#include <memory> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
bool PityTransport::debug_log_enabled = false; |
||||
|
|
||||
|
PityTransport::PityTransport(std::string inboxDir, Endpoints& endpoints) : |
||||
|
_inboxDir{ inboxDir }, _endpoints{ endpoints } |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void PityTransport::sendMsg(const std::string nodename, const std::string& msg) const |
||||
|
{ |
||||
|
pEpLogClass("Address: " + nodename + " msg: " + msg); |
||||
|
|
||||
|
// HACK TODO
|
||||
|
std::string nodename_normalized = AbstractPityUnit::_normalizeName(nodename); |
||||
|
|
||||
|
bool found = false; |
||||
|
std::string dir; |
||||
|
try { |
||||
|
dir = _endpoints.at(nodename_normalized); |
||||
|
} catch (std::out_of_range&) { |
||||
|
throw std::runtime_error("no such nodename: " + nodename_normalized); |
||||
|
} |
||||
|
Utils::dir_ensure(dir); |
||||
|
std::stringstream filename; |
||||
|
// collision detect
|
||||
|
do { |
||||
|
filename << dir << Utils::random_string(97, 122, 16) << ".pitymsg"; |
||||
|
} while (Utils::path_exists(filename.str())); |
||||
|
// create
|
||||
|
std::ofstream msgfile = Utils::file_create(filename.str()); |
||||
|
// write
|
||||
|
msgfile << msg; |
||||
|
} |
||||
|
|
||||
|
bool PityTransport::hasMsg() const |
||||
|
{ |
||||
|
bool ret = false; |
||||
|
pEpLogClass("called"); |
||||
|
Utils::dir_ensure(_inboxDir); |
||||
|
auto msg_filenames = Utils::dir_list_files(_inboxDir); |
||||
|
ret = msg_filenames.size() > 0; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// Non-blocking
|
||||
|
// throws underflow_error if inbox empty
|
||||
|
std::string PityTransport::pollMsg() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
std::string ret; |
||||
|
Utils::dir_ensure(_inboxDir); |
||||
|
auto msg_filenames = Utils::dir_list_files(_inboxDir); |
||||
|
if (!msg_filenames.empty()) { |
||||
|
std::string msg_filename = msg_filenames.at(0); |
||||
|
std::string msg_path = _inboxDir + "/" + msg_filename; |
||||
|
pEpLogClass("Reading file: " + msg_filename); |
||||
|
ret = Utils::file_read(msg_path); |
||||
|
Utils::path_delete(msg_path); |
||||
|
} else { |
||||
|
throw std::underflow_error("inbox empty: " + _inboxDir); |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// Blocking
|
||||
|
// Returns when a msg has been received
|
||||
|
std::string PityTransport::receiveMsg(int poll_interval) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
std::string ret; |
||||
|
bool retry = false; |
||||
|
do { |
||||
|
try { |
||||
|
ret = pollMsg(); |
||||
|
retry = false; |
||||
|
} catch (const std::underflow_error&) { |
||||
|
pEpLogClass("polling again in [ms]: " + std::to_string(poll_interval) + "..."); |
||||
|
Utils::sleep_millis(poll_interval); |
||||
|
retry = true; |
||||
|
} |
||||
|
} while (retry); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
@ -0,0 +1,45 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYTRANSPORT_HH |
||||
|
#define PITYTEST_PITYTRANSPORT_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include <vector> |
||||
|
#include <memory> |
||||
|
#include <unordered_map> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
// Address - Dir
|
||||
|
using Endpoints = std::unordered_map<std::string, std::string>; |
||||
|
|
||||
|
class PityTransport { |
||||
|
public: |
||||
|
// Constructors
|
||||
|
PityTransport() = delete; |
||||
|
explicit PityTransport(std::string inboxDir, Endpoints& endpoints); |
||||
|
|
||||
|
// Getters
|
||||
|
//Transport
|
||||
|
bool hasMsg() const; |
||||
|
void sendMsg(const std::string nodename, const std::string& msg) const; |
||||
|
std::string pollMsg() const; |
||||
|
std::string receiveMsg(int poll_interval = 100) const; |
||||
|
|
||||
|
//internal logging
|
||||
|
static bool debug_log_enabled; |
||||
|
Adapter::pEpLog::pEpLogger logger_debug{ "PityTransport", debug_log_enabled }; |
||||
|
|
||||
|
private: |
||||
|
std::string _inboxDir; |
||||
|
Endpoints& _endpoints; |
||||
|
|
||||
|
//internal logging
|
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // PITYTEST_PITYTRANSPORT_HH
|
@ -0,0 +1,88 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYTREE_HH |
||||
|
#define PITYTEST_PITYTREE_HH |
||||
|
|
||||
|
//#include "../../../src/pEpLog.hh"
|
||||
|
#include <string> |
||||
|
#include <map> |
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
#include <type_traits> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
template<class T> |
||||
|
class PityTree { |
||||
|
// TODO: NEEEEED THIS
|
||||
|
// static_assert(std::is_base_of<PityTree<T>, T>::value, "PityTree<T> must be a base of T");
|
||||
|
public: |
||||
|
using ChildObj = std::shared_ptr<T>; |
||||
|
using ChildObjs = std::vector<ChildObj>; |
||||
|
using ChildRef = std::pair<const std::string, T&>; |
||||
|
using ChildRefs = std::map<const std::string, T&>; |
||||
|
|
||||
|
// Constructors
|
||||
|
explicit PityTree(T& self, const std::string& name); |
||||
|
explicit PityTree(T& self, const std::string& name, T& parent); |
||||
|
explicit PityTree(const PityTree& rhs, T& owner); |
||||
|
|
||||
|
// copy-assign
|
||||
|
// PityTree& operator=(const PityTree<T>& rhs);
|
||||
|
|
||||
|
// clone
|
||||
|
virtual PityTree* clone() = 0; |
||||
|
|
||||
|
// Append
|
||||
|
// creates a new instance of CT, add the new instance as child and returns a ref to it
|
||||
|
template<typename CT, typename... Args> |
||||
|
CT& addNew(Args&&... args); |
||||
|
|
||||
|
// Creates a copy, adds the copy as child and returns a ref to it
|
||||
|
template<typename CT> |
||||
|
CT& addCopy(const CT&& child, const std::string& new_name = ""); |
||||
|
|
||||
|
template<typename CT> |
||||
|
CT& addCopy(const CT& child, const std::string& new_name = ""); |
||||
|
|
||||
|
// Just adds child as a non-owned reference.
|
||||
|
T& addRef(T& child); |
||||
|
|
||||
|
// Query
|
||||
|
virtual T& getSelf() = 0; |
||||
|
T* getParent() const; |
||||
|
ChildRefs getChildRefs() const; |
||||
|
int getChildCount() const; |
||||
|
T& getChild(const std::string& name); |
||||
|
T& getRoot(); |
||||
|
|
||||
|
void setName(const std::string& name); |
||||
|
std::string getName() const; |
||||
|
std::string getPath() const; |
||||
|
bool isRoot() const; // true if has no parent
|
||||
|
|
||||
|
std::string to_string(bool recursive = true, int indent = 0); |
||||
|
|
||||
|
//TODO HACK in PityTransport, this should be private
|
||||
|
static std::string _normalizeName(std::string name); |
||||
|
|
||||
|
virtual ~PityTree() = default; |
||||
|
|
||||
|
protected: |
||||
|
void setParent(T* const parent); |
||||
|
|
||||
|
private: |
||||
|
void _copyChildRefs(const PityTree<T>& rhs); |
||||
|
// Fields
|
||||
|
std::string _nodename; |
||||
|
T& _self; |
||||
|
T* _parent; //nullptr if RootUnit
|
||||
|
ChildRefs _childrefs; // map to guarantee uniqueness of sibling-names
|
||||
|
ChildObjs _childobjs; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#include "PityTree.hxx" |
||||
|
#endif |
@ -0,0 +1,220 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYTREE_HXX |
||||
|
#define PITYTEST_PITYTREE_HXX |
||||
|
|
||||
|
#include "PityTree.hh" |
||||
|
#include <memory> |
||||
|
#include <sstream> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
|
||||
|
// RootNode
|
||||
|
template<class T> |
||||
|
PityTree<T>::PityTree(T& self, const std::string& name) : |
||||
|
_self{ self }, _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, |
||||
|
_childobjs{} |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
// LeafNode
|
||||
|
template<class T> |
||||
|
PityTree<T>::PityTree(T& self, const std::string& name, T& parent) : |
||||
|
_self(self), _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, |
||||
|
_childobjs{} |
||||
|
{ |
||||
|
parent.addRef(_self); |
||||
|
} |
||||
|
|
||||
|
// Copy
|
||||
|
template<class T> |
||||
|
PityTree<T>::PityTree(const PityTree<T>& rhs, T& owner) : _self{ owner } |
||||
|
{ |
||||
|
_nodename = rhs._nodename; |
||||
|
_parent = nullptr; |
||||
|
_copyChildRefs(rhs); |
||||
|
} |
||||
|
|
||||
|
// template<class T>
|
||||
|
// PityTree<T>& PityTree<T>::operator=(const PityTree<T>& rhs)
|
||||
|
// {
|
||||
|
// _nodename = rhs._nodename;
|
||||
|
// _parent = nullptr;
|
||||
|
// _copyChildRefs(rhs);
|
||||
|
// return *this;
|
||||
|
// }
|
||||
|
//
|
||||
|
template<typename T> |
||||
|
template<typename CT, typename... Args> |
||||
|
CT& PityTree<T>::addNew(Args&&... args) |
||||
|
{ |
||||
|
static_assert(std::is_base_of<T, CT>::value, "T must be base of CT"); |
||||
|
std::shared_ptr<CT> tmp = std::make_shared<CT>(std::forward<Args>(args)...); |
||||
|
_childobjs.push_back(tmp); |
||||
|
addRef(*tmp.get()); |
||||
|
return *tmp.get(); |
||||
|
} |
||||
|
|
||||
|
template<typename T> |
||||
|
template<typename CT> |
||||
|
CT& PityTree<T>::addCopy(const CT&& child, const std::string& new_name) |
||||
|
{ |
||||
|
static_assert(std::is_base_of<T, CT>::value, "PityTree<T> must be a base of T"); |
||||
|
CT* tmpraw = new CT(child); |
||||
|
_childobjs.push_back(ChildObj(tmpraw)); |
||||
|
if (new_name != "") { |
||||
|
tmpraw->setName(new_name); |
||||
|
} |
||||
|
addRef(*tmpraw); |
||||
|
return *tmpraw; |
||||
|
} |
||||
|
|
||||
|
template<typename T> |
||||
|
template<typename CT> |
||||
|
CT& PityTree<T>::addCopy(const CT& child, const std::string& new_name) |
||||
|
{ |
||||
|
return addCopy(std::move(child)); |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
T& PityTree<T>::addRef(T& child) |
||||
|
{ |
||||
|
child.setParent(&_self); |
||||
|
_childrefs.insert(ChildRef(child.getName(), child)); |
||||
|
return child; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
void PityTree<T>::setParent(T* parent) |
||||
|
{ |
||||
|
_parent = parent; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
T* PityTree<T>::getParent() const |
||||
|
{ |
||||
|
return _parent; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
bool PityTree<T>::isRoot() const |
||||
|
{ |
||||
|
if (_parent == nullptr) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
void PityTree<T>::setName(const std::string& name) |
||||
|
{ |
||||
|
_nodename = name; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
std::string PityTree<T>::getName() const |
||||
|
{ |
||||
|
return _nodename; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
std::string PityTree<T>::getPath() const |
||||
|
{ |
||||
|
std::string ret; |
||||
|
|
||||
|
if (!isRoot()) { |
||||
|
ret = _parent->getPath() + "/" + getName(); |
||||
|
} else { |
||||
|
ret = getName(); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
std::string PityTree<T>::to_string(bool recursive, int indent) |
||||
|
{ |
||||
|
std::string ret; |
||||
|
std::stringstream builder; |
||||
|
builder << std::string(indent * 4, ' '); |
||||
|
builder << getName(); |
||||
|
builder << std::endl; |
||||
|
ret = builder.str(); |
||||
|
|
||||
|
if (recursive) { |
||||
|
if (!getChildRefs().empty()) { |
||||
|
indent++; |
||||
|
for (ChildRef child : getChildRefs()) { |
||||
|
ret += child.second.to_string(true, indent); |
||||
|
} |
||||
|
indent--; |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
T& PityTree<T>::getRoot() |
||||
|
{ |
||||
|
if (!isRoot()) { |
||||
|
return _parent->getRoot(); |
||||
|
} else { |
||||
|
return _self; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
typename PityTree<T>::ChildRefs PityTree<T>::getChildRefs() const |
||||
|
{ |
||||
|
return _childrefs; |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
T& PityTree<T>::getChild(const std::string& name) |
||||
|
{ |
||||
|
T* ret = nullptr; |
||||
|
try { |
||||
|
ret = &getChildRefs().at(name); |
||||
|
} catch (const std::exception& e) { |
||||
|
throw std::invalid_argument("PityNode not found: '" + name + "'"); |
||||
|
} |
||||
|
return *ret; |
||||
|
} |
||||
|
|
||||
|
// name is alphanumeric only (everything else will be replaced by an underscore)
|
||||
|
// static
|
||||
|
template<class T> |
||||
|
std::string PityTree<T>::_normalizeName(std::string name) |
||||
|
{ |
||||
|
replace_if( |
||||
|
name.begin(), |
||||
|
name.end(), |
||||
|
[](char c) -> bool { return !isalnum(c); }, |
||||
|
'_'); |
||||
|
|
||||
|
return name; |
||||
|
} |
||||
|
|
||||
|
// When you copy a treenode, you need to create a copy of all children
|
||||
|
// and take ownership
|
||||
|
template<class T> |
||||
|
void PityTree<T>::_copyChildRefs(const PityTree<T>& rhs) |
||||
|
{ |
||||
|
for (const ChildRef& cr : rhs.getChildRefs()) { |
||||
|
_childobjs.push_back(ChildObj(cr.second.clone())); |
||||
|
T& ret = *_childobjs.back().get(); |
||||
|
addRef(ret); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
int PityTree<T>::getChildCount() const |
||||
|
{ |
||||
|
return _childrefs.size(); |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif |
@ -0,0 +1,75 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYUNIT_HH |
||||
|
#define PITYTEST_PITYUNIT_HH |
||||
|
|
||||
|
#include "../../../src/pEpLog.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include "AbstractPityUnit.hh" |
||||
|
#include "fs_mutex.hh" |
||||
|
#include "PityTransport.hh" |
||||
|
#include <string> |
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
//TODO We need a context basetype
|
||||
|
class PityBaseCTX { |
||||
|
}; |
||||
|
|
||||
|
template<class TestContext = PityBaseCTX> |
||||
|
class PityUnit : public AbstractPityUnit { |
||||
|
public: |
||||
|
// Test success if TestFunction:
|
||||
|
// * does not throw
|
||||
|
// * returns 0
|
||||
|
using TestFunction = std::function<int(PityUnit<TestContext>&, TestContext*)>; |
||||
|
|
||||
|
// Constructors
|
||||
|
PityUnit() = delete; |
||||
|
explicit PityUnit<TestContext>( |
||||
|
const std::string& name, |
||||
|
TestFunction test_func = nullptr, |
||||
|
TestContext* ctx = nullptr, |
||||
|
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
||||
|
|
||||
|
explicit PityUnit<TestContext>( |
||||
|
AbstractPityUnit& parent, |
||||
|
const std::string& name, |
||||
|
TestFunction test_func = nullptr, |
||||
|
TestContext* ctx = nullptr, |
||||
|
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
||||
|
|
||||
|
PityUnit<TestContext>(const PityUnit<TestContext>& rhs); |
||||
|
|
||||
|
// copy-assign
|
||||
|
PityUnit<TestContext>& operator=(const PityUnit<TestContext>& rhs); |
||||
|
|
||||
|
PityUnit<TestContext>& getSelf() override; |
||||
|
// clone
|
||||
|
PityUnit<TestContext>* clone() override; |
||||
|
|
||||
|
void setContext(TestContext* ctx); |
||||
|
void setContext(TestContext ctx); |
||||
|
TestContext* getContext() const; |
||||
|
|
||||
|
protected: |
||||
|
void _runSelf() override; |
||||
|
|
||||
|
private: |
||||
|
void _copyContext(const PityUnit<TestContext>& rhs); |
||||
|
|
||||
|
// Fields
|
||||
|
// nullptr if inherited
|
||||
|
TestContext* _ctx; |
||||
|
std::shared_ptr<TestContext> _owned_ctx; // if you copy
|
||||
|
TestFunction _test_func; |
||||
|
}; |
||||
|
}; // namespace PityTest11
|
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#include "PityUnit.hxx" |
||||
|
|
||||
|
#endif // PITYTEST_PITYUNIT_HH
|
@ -0,0 +1,136 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PITYTEST_PITYUNIT_HXX |
||||
|
#define PITYTEST_PITYUNIT_HXX |
||||
|
|
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include "PityUnit.hh" |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <unistd.h> |
||||
|
#include <cstdlib> |
||||
|
#include <sys/stat.h> |
||||
|
#include <functional> |
||||
|
#include <algorithm> |
||||
|
#include <exception> |
||||
|
#include <memory> |
||||
|
#include <sys/wait.h> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext>::PityUnit( |
||||
|
const std::string &name, |
||||
|
TestFunction test_func, |
||||
|
TestContext *ctx, |
||||
|
ExecutionMode exec_mode) : |
||||
|
AbstractPityUnit(name, exec_mode), |
||||
|
_ctx{ ctx }, _test_func{ test_func } |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext>::PityUnit( |
||||
|
AbstractPityUnit &parent, |
||||
|
const std::string &name, |
||||
|
TestFunction test_func, |
||||
|
TestContext *ctx, |
||||
|
ExecutionMode exec_mode) : |
||||
|
AbstractPityUnit(parent, name, exec_mode), |
||||
|
_ctx{ ctx }, _test_func{ test_func } |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext>::PityUnit(const PityUnit<TestContext> &rhs) : |
||||
|
AbstractPityUnit(rhs, *this) |
||||
|
{ |
||||
|
_copyContext(rhs); |
||||
|
_test_func = TestFunction(rhs._test_func); |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext> &PityUnit<TestContext>::operator=(const PityUnit<TestContext> &rhs) |
||||
|
{ |
||||
|
_copyContext(rhs); |
||||
|
_test_func = TestFunction(rhs._test_func); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext> &PityUnit<TestContext>::getSelf() |
||||
|
{ |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
PityUnit<TestContext> *PityUnit<TestContext>::clone() |
||||
|
{ |
||||
|
return new PityUnit<TestContext>(*this); |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
void PityUnit<TestContext>::_runSelf() |
||||
|
{ |
||||
|
if (_test_func != nullptr) { |
||||
|
try { |
||||
|
_test_func(*this, getContext()); |
||||
|
logH3(_status_string("\033[1m\033[32mSUCCESS" + Utils::to_termcol(_color()))); |
||||
|
} catch (const std::exception &e) { |
||||
|
_logRaw("reason: " + std::string(e.what())); |
||||
|
logH3(_status_string("\033[1m\033[31mFAILED" + Utils::to_termcol(_color()))); |
||||
|
} |
||||
|
} else { |
||||
|
_logRaw("No function to execute"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Inherited (if null see parent recursively)
|
||||
|
template<class TestContext> |
||||
|
TestContext *PityUnit<TestContext>::getContext() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
TestContext *ret = nullptr; |
||||
|
|
||||
|
if (_ctx != nullptr) { |
||||
|
ret = _ctx; |
||||
|
} else { |
||||
|
if (!isRoot()) { |
||||
|
ret = (dynamic_cast<PityUnit<TestContext> *>(getParent()))->getContext(); |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
void PityUnit<TestContext>::_copyContext(const PityUnit<TestContext> &rhs) |
||||
|
{ |
||||
|
auto *tmp = rhs.getContext(); |
||||
|
if (tmp != nullptr) { |
||||
|
_owned_ctx = std::shared_ptr<TestContext>(new TestContext(*tmp)); |
||||
|
_ctx = tmp; |
||||
|
} else { |
||||
|
_ctx = nullptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
void PityUnit<TestContext>::setContext(TestContext *ctx) |
||||
|
{ |
||||
|
_ctx = ctx; |
||||
|
} |
||||
|
|
||||
|
template<class TestContext> |
||||
|
void PityUnit<TestContext>::setContext(TestContext ctx) |
||||
|
{ |
||||
|
_owned_ctx = std::shared_ptr<TestContext>(new TestContext(ctx)); |
||||
|
_ctx = _owned_ctx.get(); |
||||
|
} |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
|
||||
|
#endif // PITYTEST_PITYUNIT_HXX
|
@ -0,0 +1,41 @@ |
|||||
|
#include "fs_mutex.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include<fstream> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
fs_mutex::fs_mutex(std::string mutexpath) : mutexpath{ mutexpath } {} |
||||
|
|
||||
|
void fs_mutex::aquire() const |
||||
|
{ |
||||
|
if (mutexpath.empty()) { |
||||
|
throw std::runtime_error("no mutexpath set"); |
||||
|
} else { |
||||
|
std::string mutex_file = mutexpath; |
||||
|
while (Utils::path_exists(mutex_file)) { |
||||
|
Utils::sleep_millis(2); |
||||
|
} |
||||
|
std::ofstream msgfile = Utils::file_create(mutexpath); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void fs_mutex::release() const |
||||
|
{ |
||||
|
if (mutexpath.empty()) { |
||||
|
throw std::runtime_error("no mutexpath set"); |
||||
|
} else { |
||||
|
|
||||
|
try { |
||||
|
Utils::path_delete(mutexpath); |
||||
|
// Give others a chance to pickup
|
||||
|
Utils::sleep_millis(4); |
||||
|
} catch (...) { |
||||
|
// pEpLogClass("Error releasing fsmutex");
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace PityTest
|
||||
|
} // namespace pEp
|
||||
|
|
@ -0,0 +1,25 @@ |
|||||
|
#ifndef FS_MUTEX |
||||
|
#define FS_MUTEX |
||||
|
|
||||
|
#include <iostream> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PityTest11 { |
||||
|
// a very primitive IPC sync method
|
||||
|
// also unreliable
|
||||
|
// but good enough for what i just needed it for
|
||||
|
class fs_mutex { |
||||
|
public: |
||||
|
fs_mutex() = delete; |
||||
|
fs_mutex(std::string mutexpath); |
||||
|
|
||||
|
void aquire() const; |
||||
|
void release() const; |
||||
|
|
||||
|
private: |
||||
|
const std::string mutexpath; |
||||
|
}; |
||||
|
} // namespace PityTest11
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // FS_MUTEX
|
@ -0,0 +1,32 @@ |
|||||
|
#include "../src/PityTest.hh" |
||||
|
#include <iostream> |
||||
|
#include <exception> |
||||
|
|
||||
|
using namespace pEp::PityTest11; |
||||
|
void not_throwing() {} |
||||
|
|
||||
|
void throwing() |
||||
|
{ |
||||
|
throw std::runtime_error{ "Fsd" }; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
|
||||
|
PITYASSERT(true, "thats wrong"); |
||||
|
try { |
||||
|
PITYASSERT(false, "thats correct"); |
||||
|
throw std::runtime_error("PITYASSERT(false) does not throw"); |
||||
|
} catch (const PityAssertException& pae) { |
||||
|
} |
||||
|
|
||||
|
PITYASSERT(true, "thats wrong"); |
||||
|
|
||||
|
PITYASSERT_THROWS(throwing(), "is actually throwing "); |
||||
|
|
||||
|
try { |
||||
|
PITYASSERT_THROWS(not_throwing(), "is actually not throwing"); |
||||
|
throw std::runtime_error("PITYASSERT(false) does not throw"); |
||||
|
} catch (const PityAssertException& pae) { |
||||
|
} |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
#include "../src/PityTest.hh" |
||||
|
#include "../../../src/utils.hh" |
||||
|
#include <iostream> |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
|
||||
|
struct CTXExecmodes { |
||||
|
int sleepmilis; |
||||
|
int rep_count; |
||||
|
}; |
||||
|
|
||||
|
using TestContext = CTXExecmodes; |
||||
|
using TestUnit = PityUnit<TestContext>; |
||||
|
|
||||
|
int do_some_work(TestUnit& pity, TestContext* ctx) |
||||
|
{ |
||||
|
int i = 0; |
||||
|
while (i < ctx->rep_count) { |
||||
|
pity.log(pity.getName() + " - " + to_string(i)); |
||||
|
Utils::sleep_millis(ctx->sleepmilis); |
||||
|
i++; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
// DEBUG Logging of PityTestUnit itself
|
||||
|
TestUnit::debug_log_enabled = false; |
||||
|
CTXExecmodes ctxe; |
||||
|
ctxe.sleepmilis = 100; |
||||
|
ctxe.rep_count = 10; |
||||
|
|
||||
|
// NEW API
|
||||
|
{ |
||||
|
// Suite
|
||||
|
TestUnit suite = TestUnit("Test Execution Model"); |
||||
|
|
||||
|
// Groups
|
||||
|
auto grp1 = suite.addNew<TestUnit>( |
||||
|
"grp1", |
||||
|
do_some_work, |
||||
|
&ctxe, |
||||
|
TestUnit::ExecutionMode::PROCESS_PARALLEL); |
||||
|
|
||||
|
auto grp2 = suite.addNew<TestUnit>( |
||||
|
"grp2", |
||||
|
do_some_work, |
||||
|
&ctxe, |
||||
|
TestUnit::ExecutionMode::PROCESS_PARALLEL); |
||||
|
|
||||
|
// Units
|
||||
|
grp1.addNew<TestUnit>("test1.1", do_some_work); |
||||
|
grp1.addNew<TestUnit>("test1.2", do_some_work); |
||||
|
|
||||
|
// Units
|
||||
|
grp2.addNew<TestUnit>("unit_2.1", do_some_work); |
||||
|
grp2.addNew<TestUnit>("unit_2.2", do_some_work); |
||||
|
|
||||
|
suite.run(); |
||||
|
} |
||||
|
// Old API
|
||||
|
{ |
||||
|
// The RootNode is the
|
||||
|
TestUnit root_old = TestUnit{ "Test Execution Model" }; |
||||
|
|
||||
|
// Subprocess 1
|
||||
|
TestUnit test1 = TestUnit{ root_old, |
||||
|
"node1", |
||||
|
do_some_work, |
||||
|
&ctxe, |
||||
|
TestUnit::ExecutionMode::PROCESS_PARALLEL }; |
||||
|
|
||||
|
TestUnit test1_1 = TestUnit{ test1, "test1.1", do_some_work }; |
||||
|
|
||||
|
TestUnit test1_2 = TestUnit{ test1, "test1.2", do_some_work }; |
||||
|
|
||||
|
// Subprocess 2
|
||||
|
TestUnit test2 = TestUnit{ root_old, |
||||
|
"node2", |
||||
|
do_some_work, |
||||
|
&ctxe, |
||||
|
TestUnit::ExecutionMode::PROCESS_PARALLEL }; |
||||
|
|
||||
|
TestUnit test2_1 = TestUnit{ test2, "test2.1", do_some_work }; |
||||
|
|
||||
|
TestUnit test2_2 = TestUnit{ test2, "test2.2", do_some_work }; |
||||
|
|
||||
|
root_old.run(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
#include "../src/PityTest.hh" |
||||
|
#include <iostream> |
||||
|
#include <algorithm> |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
// eeks-test
|
||||
|
// The test framework for geeks without the g
|
||||
|
|
||||
|
|
||||
|
class Car { |
||||
|
private: |
||||
|
int gear_nr = 0; |
||||
|
|
||||
|
public: |
||||
|
void setGear(int nr) |
||||
|
{ |
||||
|
gear_nr = nr; |
||||
|
} |
||||
|
|
||||
|
void drive() |
||||
|
{ |
||||
|
if (gear_nr > 0 && gear_nr <= 6) { |
||||
|
cout << "cruising" << endl; |
||||
|
} else { |
||||
|
throw runtime_error{ "invalid gear" }; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
class CarTestModel { |
||||
|
public: |
||||
|
CarTestModel(const string& name) : name{ name }, car{} {} |
||||
|
|
||||
|
string name{}; |
||||
|
Car car; |
||||
|
}; |
||||
|
|
||||
|
int test_setGear(PityUnit<CarTestModel>& node, CarTestModel* ctx) |
||||
|
{ |
||||
|
int gear = 1; |
||||
|
node.log("Setting gear to: " + to_string(gear)); |
||||
|
ctx->car.setGear(gear); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_drive(PityUnit<CarTestModel>& node, CarTestModel* ctx) |
||||
|
{ |
||||
|
ctx->car.drive(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
// Linear Test
|
||||
|
CarTestModel model{ "CarTestModel" }; |
||||
|
PityUnit<CarTestModel> testnode_car{ "test car", nullptr, &model }; |
||||
|
PityUnit<CarTestModel> testnode_setGear{ testnode_car, "test car setGear()", test_setGear }; |
||||
|
PityUnit<CarTestModel> testnode_driv{ testnode_setGear, "test car drive()", &test_drive }; |
||||
|
|
||||
|
PityUnit<CarTestModel> testnode_driv_before_gear{ testnode_car, |
||||
|
"testnode_driv_before_gear", |
||||
|
&test_drive }; |
||||
|
|
||||
|
testnode_car.run(); |
||||
|
} |
@ -0,0 +1,161 @@ |
|||||
|
#include "../src/PityTree.hh" |
||||
|
#include "../src/PityTest.hh" |
||||
|
#include "../../../src/std_utils.hh" |
||||
|
#include "../../../src/utils.hh" |
||||
|
#include <iostream> |
||||
|
#include <exception> |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
class AbstractNode : public PityTree<AbstractNode> { |
||||
|
public: |
||||
|
// Constructors
|
||||
|
AbstractNode() = delete; |
||||
|
explicit AbstractNode(const std::string &name); |
||||
|
explicit AbstractNode(const std::string &name, AbstractNode &parent); |
||||
|
AbstractNode(const AbstractNode &rhs, AbstractNode &self); |
||||
|
|
||||
|
// methods
|
||||
|
virtual int implMe(int magic_nr) = 0; |
||||
|
AbstractNode& getSelf() override = 0; |
||||
|
AbstractNode *clone() override = 0; |
||||
|
|
||||
|
// fields
|
||||
|
std::string color; |
||||
|
int age{}; |
||||
|
}; |
||||
|
|
||||
|
AbstractNode::AbstractNode(const std::string &name) : PityTree<AbstractNode>(*this, name) {} |
||||
|
|
||||
|
AbstractNode::AbstractNode(const std::string &name, AbstractNode &parent) : |
||||
|
PityTree<AbstractNode>(*this, name, parent) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
AbstractNode::AbstractNode(const AbstractNode &rhs, AbstractNode &self) : |
||||
|
PityTree<AbstractNode>(rhs, self) |
||||
|
{ |
||||
|
color = rhs.color; |
||||
|
age = rhs.age; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
class ANode : public AbstractNode { |
||||
|
public: |
||||
|
explicit ANode(const std::string &name); |
||||
|
explicit ANode(const std::string &name, AbstractNode &parent); |
||||
|
ANode(const ANode &rhs); |
||||
|
ANode &getSelf() override; |
||||
|
ANode *clone() override; |
||||
|
int implMe(int magic_nr) override; |
||||
|
}; |
||||
|
|
||||
|
ANode::ANode(const std::string &name) : AbstractNode(name) {} |
||||
|
ANode::ANode(const std::string &name, AbstractNode &parent) : AbstractNode(name, parent) {} |
||||
|
ANode::ANode(const ANode &rhs) : AbstractNode(rhs, *this) {} |
||||
|
|
||||
|
int ANode::implMe(int magic_nr) |
||||
|
{ |
||||
|
return 23; |
||||
|
} |
||||
|
|
||||
|
ANode &ANode::getSelf() |
||||
|
{ |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
ANode *ANode::clone() |
||||
|
{ |
||||
|
return new ANode(*this); |
||||
|
} |
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
class BNode : public AbstractNode { |
||||
|
public: |
||||
|
explicit BNode(const std::string &name); |
||||
|
explicit BNode(const std::string &name, AbstractNode &parent); |
||||
|
BNode(const BNode &rhs); |
||||
|
BNode &getSelf() override; |
||||
|
BNode *clone() override; |
||||
|
int implMe(int magic_nr) override; |
||||
|
}; |
||||
|
|
||||
|
BNode::BNode(const std::string &name) : AbstractNode(name) {} |
||||
|
BNode::BNode(const std::string &name, AbstractNode &parent) : AbstractNode(name, parent) {} |
||||
|
BNode::BNode(const BNode &rhs) : AbstractNode(rhs, *this) {} |
||||
|
|
||||
|
int BNode::implMe(int magic_nr) |
||||
|
{ |
||||
|
return 42; |
||||
|
} |
||||
|
|
||||
|
BNode &BNode::getSelf() |
||||
|
{ |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
BNode *BNode::clone() |
||||
|
{ |
||||
|
return new BNode(*this); |
||||
|
} |
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
void not_throwing() |
||||
|
{ |
||||
|
throw std::runtime_error{ "Fsd" }; |
||||
|
} |
||||
|
|
||||
|
void throwing() |
||||
|
{ |
||||
|
throw std::runtime_error{ "Fsd" }; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
// Create lone node
|
||||
|
ANode a{ "a" }; |
||||
|
std::cout << a.getPath() << std::endl; |
||||
|
PITYASSERT(a.isRoot() == true, "a"); |
||||
|
PITYASSERT(a.getName() == "a", "b"); |
||||
|
PITYASSERT(&(a.getRoot()) == &a, "c"); |
||||
|
PITYASSERT(a.getParent() == nullptr, "d"); |
||||
|
PITYASSERT(a.getChildRefs().size() == 0, "e"); |
||||
|
|
||||
|
// Create node here, and make it a child of another node
|
||||
|
BNode b{ "b", a }; |
||||
|
std::cout << b.getPath() << std::endl; |
||||
|
PITYASSERT(a.isRoot() == true, "f"); |
||||
|
PITYASSERT(&(a.getRoot()) == &a, "g"); |
||||
|
PITYASSERT(a.getParent() == nullptr, "1"); |
||||
|
PITYASSERT(a.getChildRefs().size() == 1, "2"); |
||||
|
|
||||
|
PITYASSERT(&b == &(a.getChild("b")), "3"); |
||||
|
PITYASSERT_THROWS(a.getChild("invalid"), "4"); |
||||
|
PITYASSERT(b.isRoot() == false, "5"); |
||||
|
PITYASSERT(&(b.getRoot()) == &a, "6"); |
||||
|
PITYASSERT(b.getParent() == &a, "7"); |
||||
|
PITYASSERT(b.getChildRefs().size() == 0, "8"); |
||||
|
|
||||
|
// Create a copy of the node in the parent node
|
||||
|
b.addNew<ANode>("c").addNew<ANode>("d"); |
||||
|
std::cout << a.to_string() << std::endl; |
||||
|
|
||||
|
b.addNew<BNode>("c1").addNew<BNode>("e"); |
||||
|
std::cout << a.to_string() << std::endl; |
||||
|
|
||||
|
b.getChild("c1").getChild("e").addCopy(ANode(a), "a1"); |
||||
|
std::cout << a.to_string() << std::endl; |
||||
|
|
||||
|
a.getChild("b").addCopy(ANode(a), a.getName() + "1"); |
||||
|
std::cout << a.to_string() << std::endl; |
||||
|
|
||||
|
ANode a2 = ANode(a); |
||||
|
a2.setName("a2"); |
||||
|
std::cout << a2.to_string() << std::endl; |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
#include "../src/PityTest.hh" |
||||
|
#include <iostream> |
||||
|
#include <algorithm> |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
|
||||
|
using TestContext = void; |
||||
|
using TestUnit = PityUnit<>; |
||||
|
|
||||
|
//TODO: Add HOME testing
|
||||
|
void printHomeDir(TestUnit& myself) |
||||
|
{ |
||||
|
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid())));
|
||||
|
// cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl;
|
||||
|
setenv("HOME", myself.getProcessDir().c_str(), 1); |
||||
|
myself.log("HOME=" + string(getenv("HOME"))); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
PityUnit<>::debug_log_enabled = false; |
||||
|
// Suite
|
||||
|
TestUnit suite = TestUnit{ "test_processdirs" }; |
||||
|
|
||||
|
// 1
|
||||
|
suite |
||||
|
.addNew<TestUnit>( |
||||
|
"node 1", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/", "node 1"); |
||||
|
return 0; |
||||
|
}) |
||||
|
.addNew<TestUnit>("node 1.1", [](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/", "node 1.1"); |
||||
|
return 0; |
||||
|
}); |
||||
|
|
||||
|
// 2
|
||||
|
suite |
||||
|
.addNew<TestUnit>( |
||||
|
"node 2", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/", "node 2"); |
||||
|
return 0; |
||||
|
}) |
||||
|
.addNew<TestUnit>( |
||||
|
"node 2.1", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_2_1/", ""); |
||||
|
return 0; |
||||
|
}, |
||||
|
nullptr, |
||||
|
PityUnit<>::ExecutionMode::PROCESS_PARALLEL) |
||||
|
.addNew<TestUnit>("node 2.1.1", [](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_2_1/", ""); |
||||
|
return 0; |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
// 3
|
||||
|
suite |
||||
|
.addNew<TestUnit>( |
||||
|
"node 3", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_3/", ""); |
||||
|
return 0; |
||||
|
}, |
||||
|
nullptr, |
||||
|
PityUnit<>::ExecutionMode::PROCESS_PARALLEL) |
||||
|
.addNew<TestUnit>( |
||||
|
"node 3.1", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_3/", ""); |
||||
|
return 0; |
||||
|
}) |
||||
|
.addNew<TestUnit>( |
||||
|
"node 3.1.1", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_3/", ""); |
||||
|
return 0; |
||||
|
}) |
||||
|
.addNew<TestUnit>( |
||||
|
"node 3.1.1", |
||||
|
[](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_3_1_1/", ""); |
||||
|
return 0; |
||||
|
}, |
||||
|
nullptr, |
||||
|
PityUnit<>::ExecutionMode::PROCESS_PARALLEL) |
||||
|
.addNew<TestUnit>("node 3.1.1.1", [](TestUnit& pity, TestContext* ctx) { |
||||
|
PITYASSERT(pity.getProcessDir() == "./pitytest_data/test_processdirs/node_3_1_1/", ""); |
||||
|
return 0; |
||||
|
}); |
||||
|
|
||||
|
suite.run(); |
||||
|
} |
@ -0,0 +1,88 @@ |
|||||
|
#include "../src/PityTest.hh" |
||||
|
#include "../../../src/utils.hh" |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
using TextCTX = PityModel; |
||||
|
using TestUnit = PityUnit<TextCTX>; |
||||
|
|
||||
|
using TextCTXSwarm = PityPerspective; |
||||
|
using TestUnitSwarm = PityUnit<TextCTXSwarm>; |
||||
|
|
||||
|
int test_init(PityUnit<PityPerspective>& unit, PityPerspective* ctx) |
||||
|
{ |
||||
|
unit.log("GlobalRoot:" + unit.getGlobalRootDir()); |
||||
|
unit.log("Path:" + unit.getPath()); |
||||
|
unit.log("ProcessDir:" + unit.getProcessDir()); |
||||
|
unit.log("TransportDir:" + unit.getTransportDir()); |
||||
|
|
||||
|
PITYASSERT( |
||||
|
unit.getProcessDir() == |
||||
|
unit.getGlobalRootDir() + |
||||
|
AbstractPityUnit::_normalizeName(unit.getParentProcessUnit().getPath()) + "/", |
||||
|
"ProcessDir"); |
||||
|
PITYASSERT(std::string(getenv("HOME")) == unit.getProcessDir(), "HOME"); |
||||
|
PITYASSERT(unit.getTransportDir() == unit.getProcessDir() + "inbox/", "TransportDir"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_run(PityUnit<PityPerspective>& unit, PityPerspective* ctx) |
||||
|
{ |
||||
|
std::string msg = "Message from: " + unit.getPath(); |
||||
|
int throttle = 1000; |
||||
|
int cycles = 3; |
||||
|
for (int i = 0; i < cycles; i++) { |
||||
|
Utils::sleep_millis(throttle); |
||||
|
unit.log(std::to_string(ctx->peers.size())); |
||||
|
for (const auto& peer : ctx->peers) { |
||||
|
unit.log("sending to" + peer.addr); |
||||
|
unit.transport()->sendMsg(peer.addr, msg); |
||||
|
} |
||||
|
|
||||
|
while (unit.transport()->hasMsg()) { |
||||
|
unit.log(unit.getPath() + " - MSG RX:" + unit.transport()->receiveMsg()); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_finish(PityUnit<PityPerspective>& unit, PityPerspective* ctx) |
||||
|
{ |
||||
|
unit.log(unit.getPath() + " - DONE"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
int nodesCount = 3; |
||||
|
PityModel model{ "model_swarm", nodesCount }; |
||||
|
TestUnit suite{ "suite_swarm" }; |
||||
|
|
||||
|
PitySwarm swarm1{ "swarm1", model }; |
||||
|
for (int i = 0; i < nodesCount; i++) { |
||||
|
swarm1.addTestUnit(i, TestUnitSwarm("init", &test_init)); |
||||
|
swarm1.addTestUnit(i, TestUnitSwarm("run", &test_run)); |
||||
|
} |
||||
|
std::cout << swarm1.getSwarmUnit().to_string() << std::endl; |
||||
|
|
||||
|
// swarm2 copy of swarm1
|
||||
|
PitySwarm swarm2{ swarm1, "swarm2" }; |
||||
|
// modify
|
||||
|
for (int i = 0; i < nodesCount; i++) { |
||||
|
swarm2.addTestUnit(i, TestUnitSwarm("finish", &test_finish)); |
||||
|
} |
||||
|
// swarm2.getSwarmUnit().getChildRefs().begin()->second.setName("FDAGAFG");
|
||||
|
// swarm2.getSwarmUnit().getChildRefs().begin()->second.getChildRefs().begin()->second.setName("fsadAG");
|
||||
|
std::cout << swarm1.getSwarmUnit().to_string() << std::endl; |
||||
|
std::cout << swarm2.getSwarmUnit().to_string() << std::endl; |
||||
|
|
||||
|
suite.addRef(swarm1.getSwarmUnit()); |
||||
|
// TODO this is broken, will not be run
|
||||
|
suite.addRef(swarm2.getSwarmUnit()); |
||||
|
suite.run(); |
||||
|
|
||||
|
// swarm1.run();
|
||||
|
// Utils::readKey();
|
||||
|
// swarm2.run();
|
||||
|
} |
@ -0,0 +1,307 @@ |
|||||
|
#include "../src/listmanager_dummy.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
#include <exception> |
||||
|
#include <map> |
||||
|
#include <cassert> |
||||
|
|
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter::pEpLog; |
||||
|
using namespace pEp::Utils; |
||||
|
|
||||
|
struct lm_list { |
||||
|
string addr; |
||||
|
string mod; |
||||
|
vector<string> members; |
||||
|
}; |
||||
|
|
||||
|
struct model_test_lmd { |
||||
|
string alice; |
||||
|
string bob; |
||||
|
string carol; |
||||
|
string joe; |
||||
|
string db_path; |
||||
|
vector<lm_list> lists; |
||||
|
vector<string> lists_addr() const |
||||
|
{ |
||||
|
vector<string> ret; |
||||
|
for (const lm_list& l : this->lists) { |
||||
|
ret.push_back(l.addr); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
void apply_model(ListManagerDummy& lmd, const model_test_lmd& model) |
||||
|
{ |
||||
|
// log("apply_model()");
|
||||
|
for (const lm_list& l : model.lists) { |
||||
|
lmd.list_add(l.addr, l.mod); |
||||
|
for (const string& m : l.members) { |
||||
|
lmd.member_add(l.addr, m); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void verify_model(ListManagerDummy& lmd, const model_test_lmd& model) |
||||
|
{ |
||||
|
// log("verify_model()");
|
||||
|
assert((model.lists_addr()) == lmd.lists()); |
||||
|
for (const lm_list& l : model.lists) { |
||||
|
assert(l.members == lmd.members(l.addr)); |
||||
|
} |
||||
|
for (const lm_list& l : model.lists) { |
||||
|
assert(l.mod == lmd.moderator(l.addr)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void recreate_apply_and_verify_model(ListManagerDummy& lmd, const model_test_lmd& model) |
||||
|
{ |
||||
|
try { |
||||
|
lmd.delete_db(); |
||||
|
} catch (const exception& e) { |
||||
|
} |
||||
|
assert(!path_exists(model.db_path)); |
||||
|
apply_model(lmd, model); |
||||
|
verify_model(lmd, model); |
||||
|
} |
||||
|
|
||||
|
model_test_lmd create_default_model() |
||||
|
{ |
||||
|
model_test_lmd model; |
||||
|
model.db_path = "test_lmd.db"; |
||||
|
model.alice = "alice@peptest.org"; |
||||
|
model.bob = "bob@peptest.org"; |
||||
|
model.carol = "carol@peptest.org"; |
||||
|
model.joe = "joe@peptest.org"; |
||||
|
|
||||
|
lm_list l1; |
||||
|
l1.addr = "list1@peptest.org"; |
||||
|
l1.mod = model.alice; |
||||
|
l1.members.push_back(model.bob); |
||||
|
l1.members.push_back(model.carol); |
||||
|
|
||||
|
lm_list l2; |
||||
|
l2.addr = "list2@peptest.org"; |
||||
|
l2.mod = model.alice; |
||||
|
l2.members.push_back(model.bob); |
||||
|
l2.members.push_back(model.carol); |
||||
|
l2.members.push_back(model.joe); |
||||
|
|
||||
|
lm_list l3; |
||||
|
l3.addr = "list3@peptest.org"; |
||||
|
l3.mod = model.bob; |
||||
|
l3.members.push_back(model.carol); |
||||
|
l3.members.push_back(model.joe); |
||||
|
|
||||
|
model.lists.push_back(l1); |
||||
|
model.lists.push_back(l2); |
||||
|
model.lists.push_back(l3); |
||||
|
return model; |
||||
|
} |
||||
|
|
||||
|
model_test_lmd create_model_bad_path() |
||||
|
{ |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
model.db_path = "/wont_create_dirs/bad.db"; |
||||
|
return model; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
// pEpSQLite::log_enabled = true;
|
||||
|
ListManagerDummy::log_enabled = false; |
||||
|
|
||||
|
logH1("Testing SUCCESS conditions"); |
||||
|
{ |
||||
|
logH2("Test create new db"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
} |
||||
|
{ |
||||
|
logH2("Test re-open db"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
assert(path_exists(model.db_path)); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
verify_model(lmd, model); |
||||
|
|
||||
|
logH2("Test list_delete"); |
||||
|
lmd.list_delete(model.lists.at(2).addr); |
||||
|
model.lists.pop_back(); |
||||
|
verify_model(lmd, model); |
||||
|
|
||||
|
logH2("Test auto reopen after close()"); |
||||
|
lmd.close_db(); |
||||
|
|
||||
|
logH2("Test member_remove"); |
||||
|
lmd.member_remove(model.lists.at(0).addr, model.lists.at(0).members.at(1)); |
||||
|
model.lists.at(0).members.pop_back(); |
||||
|
verify_model(lmd, model); |
||||
|
|
||||
|
logH2("Test list_exists() - true"); |
||||
|
assert(lmd.list_exists(model.lists.at(0).addr)); |
||||
|
|
||||
|
logH2("Test list_exists() - false"); |
||||
|
assert(!lmd.list_exists("does_not_exist_for_sure")); |
||||
|
|
||||
|
logH2("Test member_exists() - true"); |
||||
|
assert(lmd.member_exists(model.lists.at(0).addr, model.lists.at(0).members.at(0))); |
||||
|
|
||||
|
logH2("Test member_exists() - false"); |
||||
|
assert(!lmd.member_exists(model.lists.at(0).addr, "does_not_exist_for_sure")); |
||||
|
|
||||
|
logH2("Test delete_db"); |
||||
|
lmd.delete_db(); |
||||
|
assert(!path_exists(model.db_path)); |
||||
|
} |
||||
|
|
||||
|
logH1("Testing ERROR conditions"); |
||||
|
{ |
||||
|
logH2("Testing success on close_db() on model_bad_path"); |
||||
|
model_test_lmd model = create_model_bad_path(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
lmd.close_db(); |
||||
|
} |
||||
|
{ |
||||
|
logH2("Testing exception on delete_db() on model_bad_path"); |
||||
|
model_test_lmd model = create_model_bad_path(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
ASSERT_EXCEPT(lmd.delete_db()); |
||||
|
} |
||||
|
{ |
||||
|
logH2("Testing exception on lists() on: on model_bad_path"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
model.db_path = "/wont_create_dirs/bad.db"; |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
ASSERT_EXCEPT(lmd.lists()); |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("list_add() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing list_add() AlreadyExistsException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.list_add(model.lists.at(0).addr, "any"); |
||||
|
assert(false); |
||||
|
} catch (const AlreadyExistsException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("list_delete() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing list_delete() DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.list_delete("does_not_exist_for_sure"); |
||||
|
assert(false); |
||||
|
} catch (const ListDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("member_add() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing member_add() AlreadyExistsException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.member_add(model.lists.at(0).addr, model.lists.at(0).members.at(0)); |
||||
|
assert(false); |
||||
|
} catch (const AlreadyExistsException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
{ |
||||
|
logH2("Testing member_add() to not existing list - DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.member_add("does_not_exist_for_sure", model.lists.at(0).members.at(0)); |
||||
|
assert(false); |
||||
|
} catch (const ListDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("member_remove() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing member_remove() not existing member - DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.member_remove(model.lists.at(0).addr, "does_not_exist_for_sure"); |
||||
|
assert(false); |
||||
|
} catch (const MemberDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
{ |
||||
|
logH2("Testing member_remove() not existing list - DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.member_remove("does_not_exist_for_sure", model.lists.at(0).members.at(0)); |
||||
|
assert(false); |
||||
|
} catch (const ListDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("moderator() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing moderator() DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.moderator("does_not_exist_for_sure"); |
||||
|
assert(false); |
||||
|
} catch (const ListDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
logH1("members() Error conditions"); |
||||
|
{ |
||||
|
logH2("Testing members() DoesNotExistException"); |
||||
|
model_test_lmd model = create_default_model(); |
||||
|
ListManagerDummy lmd(model.db_path); |
||||
|
recreate_apply_and_verify_model(lmd, model); |
||||
|
try { |
||||
|
lmd.members("does_not_exist_for_sure"); |
||||
|
assert(false); |
||||
|
} catch (const ListDoesNotExistException& e) { |
||||
|
log(nested_exception_to_string(e)); |
||||
|
} catch (...) { |
||||
|
assert(false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
logH1("All Tests SUCCESSFUL"); |
||||
|
} |
@ -0,0 +1,642 @@ |
|||||
|
#include "test_pEpSQLite.hh" |
||||
|
#include "../src/pEpSQLite.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "../src/std_utils.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
#include <fstream> |
||||
|
#include <cassert> |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Test; |
||||
|
using namespace pEp::Utils; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Test { |
||||
|
// --------------------------------- FIXTURES ---------------------------------
|
||||
|
// filenames
|
||||
|
string fixture_db_filename_new() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = "new.db"; |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
string fixture_db_filename_bad() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string db_path_bad = "/will_not_create_dirs/bad.db"; |
||||
|
return db_path_bad; |
||||
|
} |
||||
|
|
||||
|
string fixture_db_filename_existing_and_verified() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = "new.db"; |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
string fixture_db_filename_corrupt() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = "corrupt.db"; |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
// prepared db's
|
||||
|
string fixture_init_db_new() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = fixture_db_filename_new(); |
||||
|
path_ensure_not_existing(path); |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
string fixture_init_db_existing_and_verified() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = "existing.db"; |
||||
|
path_ensure_not_existing(path); |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
string fixture_init_db_corrupt() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
string path = fixture_db_filename_corrupt(); |
||||
|
path_ensure_not_existing(path); |
||||
|
ofstream db_corrupt = file_create(path); |
||||
|
db_corrupt << "G4rbage" << endl; |
||||
|
db_corrupt.close(); |
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
// instance
|
||||
|
pEpSQLite fixture_instance_of_new() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_create_instance_on_new(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_instance_of_existing_and_verified() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_create_instance_on_existing(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_instance_of_bad() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_create_instance_on_path_bad(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_instance_of_corrupt() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_create_instance_on_path_corrupt(); |
||||
|
} |
||||
|
|
||||
|
// open
|
||||
|
pEpSQLite fixture_db_open_of_new() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_createopen_db_new(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_of_existing_and_verified() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_db_verify_content_after_insert_on_tables_exist(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_of_bad() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_createopen_db_bad(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_of_corrupt() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_createopen_db_corrupt(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_after_close() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_close_after_open(); |
||||
|
} |
||||
|
|
||||
|
// tables
|
||||
|
pEpSQLite fixture_db_open_with_tables_of_new() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_db_create_tables_on_open_new(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_with_tables_of_corrupt() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_db_create_tables_on_open_corrupt(); |
||||
|
} |
||||
|
|
||||
|
// content
|
||||
|
pEpSQLite fixture_db_open_with_tables_and_content() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_db_insert_on_tables_exist(); |
||||
|
} |
||||
|
|
||||
|
// delete
|
||||
|
pEpSQLite fixture_db_open_after_delete() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_delete_file_gone_after_open_existing(); |
||||
|
} |
||||
|
|
||||
|
pEpSQLite fixture_db_open_after_close_after_delete() |
||||
|
{ |
||||
|
// TESTLOG("called");
|
||||
|
return test_delete_file_gone_after_close_new(); |
||||
|
} |
||||
|
|
||||
|
// --------------------------------- TESTS ---------------------------------
|
||||
|
|
||||
|
// instance creation
|
||||
|
// OK
|
||||
|
pEpSQLite test_create_instance_on_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db(fixture_init_db_new()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_create_instance_on_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db(fixture_init_db_existing_and_verified()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_create_instance_on_path_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db(fixture_db_filename_bad()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_create_instance_on_path_corrupt() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db(fixture_init_db_corrupt()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// db create_open (create_or_open())
|
||||
|
// OK, new db
|
||||
|
pEpSQLite test_createopen_db_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
assert(!path_exists(fixture_db_filename_new())); |
||||
|
db.create_or_open_db(); |
||||
|
assert(path_exists(fixture_db_filename_new())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK, open db
|
||||
|
pEpSQLite test_createopen_db_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_existing_and_verified(); |
||||
|
assert(path_exists(fixture_db_filename_existing_and_verified())); |
||||
|
db.create_or_open_db(); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, cant create
|
||||
|
pEpSQLite test_createopen_db_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
assert(!path_exists(fixture_db_filename_bad())); |
||||
|
pEpSQLite db = fixture_instance_of_bad(); |
||||
|
assert(!path_exists(fixture_db_filename_bad())); |
||||
|
ASSERT_EXCEPT(db.create_or_open_db()); |
||||
|
assert(!path_exists(fixture_db_filename_bad())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK(cant detect corruption)
|
||||
|
pEpSQLite test_createopen_db_corrupt() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_corrupt(); |
||||
|
assert(path_exists(fixture_db_filename_corrupt())); |
||||
|
db.create_or_open_db(); |
||||
|
assert(path_exists(fixture_db_filename_corrupt())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// close()
|
||||
|
// OK
|
||||
|
pEpSQLite test_close_before_open() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
db.close_db(); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_close_after_open() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
db.close_db(); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_close_idempotent() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
db.close_db(); |
||||
|
db.close_db(); |
||||
|
db.close_db(); |
||||
|
db.close_db(); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// create tables (execute())
|
||||
|
// OK
|
||||
|
pEpSQLite test_db_create_tables_on_open_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
db.execute("CREATE TABLE test(i,i_squared);"); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, Tables already exist
|
||||
|
pEpSQLite test_db_create_tables_open_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_existing_and_verified(); |
||||
|
ASSERT_EXCEPT(db.execute("CREATE TABLE test(i,i_squared);")); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, db closed
|
||||
|
pEpSQLite test_db_create_tables_on_open_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_bad(); |
||||
|
|
||||
|
ASSERT_EXCEPT(db.execute("CREATE TABLE test(i,i_squared);")); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, db corrupt
|
||||
|
pEpSQLite test_db_create_tables_on_open_corrupt() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_corrupt(); |
||||
|
ASSERT_EXCEPT(db.execute("CREATE TABLE test(i,i_squared);")); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// insert (execute())
|
||||
|
void insert_operation(pEpSQLite& db) |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
for (int i = 0; i < 9; i = (i + 2)) { |
||||
|
db.execute( |
||||
|
"INSERT INTO test(i,i_squared) VALUES ('" + to_string(i) + "', '" + |
||||
|
to_string(i * i) + "');"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_db_insert_on_tables_exist() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_with_tables_of_new(); |
||||
|
insert_operation(db); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, Tables missing
|
||||
|
pEpSQLite test_db_insert_on_tables_dont_exist() |
||||
|
{ |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
ASSERT_EXCEPT(insert_operation(db)); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, Tables missing
|
||||
|
pEpSQLite test_db_insert_before_open() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
ASSERT_EXCEPT(insert_operation(db)); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, Tables missing
|
||||
|
pEpSQLite test_db_insert_after_close() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_after_close(); |
||||
|
ASSERT_EXCEPT(insert_operation(db)); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// verify contents (execute())
|
||||
|
void verify_operation(pEpSQLite& db) |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
for (int i = 0; i < 9; i++) { |
||||
|
ResultSet rs = db.execute( |
||||
|
"SELECT i, i_squared FROM test " |
||||
|
"WHERE (test.i == '" + |
||||
|
to_string(i) + "');"); |
||||
|
if (i % 2) { |
||||
|
if (!rs.empty()) { |
||||
|
runtime_error e{ "Exception verifying database content" }; |
||||
|
throw(e); |
||||
|
} |
||||
|
} else { |
||||
|
if (rs.size() != 1) { |
||||
|
runtime_error e{ "Exception verifying database content" }; |
||||
|
throw(e); |
||||
|
} |
||||
|
for (const RSRecord& r : rs) { |
||||
|
const int x = stoi(r.at("i")); |
||||
|
const int x_squared = stoi(r.at("i_squared")); |
||||
|
if ((x * x) != x_squared) { |
||||
|
runtime_error e{ "Exception verifying database content" }; |
||||
|
throw(e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_db_verify_content_existing_open_db() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_existing_and_verified(); |
||||
|
verify_operation(db); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_db_verify_content_after_insert_on_tables_exist() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_with_tables_and_content(); |
||||
|
verify_operation(db); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR - no tables
|
||||
|
pEpSQLite test_db_verify_content_no_tables() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
|
||||
|
ASSERT_EXCEPT(verify_operation(db)); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR - err no data
|
||||
|
pEpSQLite test_db_verify_content_after_create_tables() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_with_tables_of_new(); |
||||
|
ASSERT_EXCEPT(verify_operation(db)); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// get_path()
|
||||
|
// OK
|
||||
|
pEpSQLite test_get_path_on_instance_good() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
assert(db.get_db_path() == fixture_db_filename_new()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_get_path_on_instance_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_bad(); |
||||
|
assert(db.get_db_path() == fixture_db_filename_bad()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// delete_db()
|
||||
|
// ERR, file not found
|
||||
|
pEpSQLite test_delete_file_gone_before_open_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
ASSERT_EXCEPT(db.delete_db()); |
||||
|
assert(!path_exists(fixture_db_filename_new())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR, file not found
|
||||
|
pEpSQLite test_delete_file_gone_before_open_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_existing_and_verified(); |
||||
|
ASSERT_EXCEPT(db.delete_db()); |
||||
|
assert(!path_exists(fixture_db_filename_existing_and_verified())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_delete_file_gone_after_close_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_after_close(); |
||||
|
db.delete_db(); |
||||
|
assert(!path_exists(fixture_db_filename_new())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_delete_file_gone_after_open_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_existing_and_verified(); |
||||
|
db.delete_db(); |
||||
|
assert(!path_exists(fixture_db_filename_existing_and_verified())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// OK
|
||||
|
pEpSQLite test_delete_file_gone_after_open_corrupt() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_corrupt(); |
||||
|
db.delete_db(); |
||||
|
assert(!path_exists(fixture_db_filename_corrupt())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// ERR
|
||||
|
pEpSQLite test_delete_file_gone_after_open_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_bad(); |
||||
|
ASSERT_EXCEPT(db.delete_db()); |
||||
|
assert(!path_exists(fixture_db_filename_bad())); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// is_open()
|
||||
|
// false
|
||||
|
pEpSQLite test_is_open_before_open_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_instance_of_new(); |
||||
|
assert(!db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// true
|
||||
|
pEpSQLite test_is_open_after_open_new() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_new(); |
||||
|
assert(db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// true
|
||||
|
pEpSQLite test_is_open_after_open_existing() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_existing_and_verified(); |
||||
|
assert(db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// false
|
||||
|
pEpSQLite test_is_open_after_open_bad() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_bad(); |
||||
|
assert(!db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// true (cant detect corruption)
|
||||
|
pEpSQLite test_is_open_after_open_corrupt() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_of_corrupt(); |
||||
|
assert(db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// false
|
||||
|
pEpSQLite test_is_open_after_close() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_after_close(); |
||||
|
assert(!db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// false
|
||||
|
pEpSQLite test_is_open_after_delete_on_open() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_after_delete(); |
||||
|
assert(!db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
|
||||
|
// false
|
||||
|
pEpSQLite test_is_open_after_delete_on_closed() |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
pEpSQLite db = fixture_db_open_after_close_after_delete(); |
||||
|
assert(!db.is_open()); |
||||
|
return db; |
||||
|
} |
||||
|
} // namespace Test
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
int main(int argc, char* argv[]) |
||||
|
{ |
||||
|
// Enable logging for all instances of pEpSQLite
|
||||
|
pEpSQLite::log_enabled = true; |
||||
|
Adapter::pEpLog::set_enabled(true); |
||||
|
// instance creation
|
||||
|
test_create_instance_on_new(); |
||||
|
test_create_instance_on_existing(); |
||||
|
test_create_instance_on_path_bad(); |
||||
|
test_create_instance_on_path_corrupt(); |
||||
|
// db create_open (create_or_open())
|
||||
|
test_createopen_db_new(); |
||||
|
test_createopen_db_existing(); |
||||
|
test_createopen_db_bad(); |
||||
|
test_createopen_db_corrupt(); |
||||
|
// close()
|
||||
|
test_close_before_open(); |
||||
|
test_close_after_open(); |
||||
|
test_close_idempotent(); |
||||
|
// create tables (execute())
|
||||
|
test_db_create_tables_on_open_new(); |
||||
|
test_db_create_tables_open_existing(); |
||||
|
test_db_create_tables_on_open_bad(); |
||||
|
test_db_create_tables_on_open_corrupt(); |
||||
|
// insert (execute())
|
||||
|
test_db_insert_on_tables_exist(); |
||||
|
test_db_insert_on_tables_dont_exist(); |
||||
|
test_db_insert_before_open(); |
||||
|
test_db_insert_after_close(); |
||||
|
// verify contents (execute())
|
||||
|
test_db_verify_content_existing_open_db(); |
||||
|
test_db_verify_content_after_insert_on_tables_exist(); |
||||
|
test_db_verify_content_no_tables(); |
||||
|
test_db_verify_content_after_create_tables(); |
||||
|
// get_path()
|
||||
|
test_get_path_on_instance_good(); |
||||
|
test_get_path_on_instance_bad(); |
||||
|
// delete_db()
|
||||
|
test_delete_file_gone_before_open_new(); |
||||
|
test_delete_file_gone_before_open_existing(); |
||||
|
test_delete_file_gone_after_close_new(); |
||||
|
test_delete_file_gone_after_open_existing(); |
||||
|
test_delete_file_gone_after_open_corrupt(); |
||||
|
test_delete_file_gone_after_open_bad(); |
||||
|
// is_open()
|
||||
|
test_is_open_before_open_new(); |
||||
|
test_is_open_after_open_new(); |
||||
|
test_is_open_after_open_existing(); |
||||
|
test_is_open_after_open_bad(); |
||||
|
test_is_open_after_open_corrupt(); |
||||
|
test_is_open_after_close(); |
||||
|
test_is_open_after_delete_on_open(); |
||||
|
test_is_open_after_delete_on_closed(); |
||||
|
|
||||
|
path_ensure_not_existing(fixture_db_filename_new()); |
||||
|
path_ensure_not_existing(fixture_db_filename_corrupt()); |
||||
|
path_ensure_not_existing(fixture_db_filename_existing_and_verified()); |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_TEST_PEPSQLITE_HH |
||||
|
#define LIBPEPADAPTER_TEST_PEPSQLITE_HH |
||||
|
|
||||
|
#include <string> |
||||
|
#include "../src/pEpSQLite.hh" |
||||
|
|
||||
|
// ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION
|
||||
|
//
|
||||
|
// THIS IS TERRIBLE, JUST TERRIBLE, THIS IS A ANTI-PATTERN
|
||||
|
// Thats the single most stupid way of writing unit test ever!!!
|
||||
|
// DONT EVER DO THIS!
|
||||
|
//
|
||||
|
// The idea is as follows:
|
||||
|
// * Tests start simple and become increasingly complex
|
||||
|
// * There are fixtures and tests, as usual
|
||||
|
// * You start with basic fixtures to write the first test
|
||||
|
// * A test becomes a fixture, if the operation is needed for another test
|
||||
|
// * You systematically cover all the states possible in which a test can be executed
|
||||
|
//
|
||||
|
// THATS JUST TERRIBLE!!!
|
||||
|
// I WILL NEVER DO THAT AGAIN!
|
||||
|
//
|
||||
|
// ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Test { |
||||
|
// FIXTURES
|
||||
|
// --------
|
||||
|
// filenames
|
||||
|
std::string fixture_db_filename_new(); |
||||
|
std::string fixture_db_filename_existing_and_verified(); |
||||
|
std::string fixture_db_filename_bad(); |
||||
|
std::string fixture_db_filename_corrupt(); |
||||
|
// prepared db's
|
||||
|
std::string fixture_init_db_new(); |
||||
|
std::string fixture_init_db_existing_and_verified(); |
||||
|
std::string fixture_init_db_corrupt(); |
||||
|
// instance
|
||||
|
pEpSQLite fixture_instance_of_new(); |
||||
|
pEpSQLite fixture_instance_of_existing_and_verified(); |
||||
|
pEpSQLite fixture_instance_of_bad(); |
||||
|
pEpSQLite fixture_instance_of_corrupt(); |
||||
|
// open
|
||||
|
pEpSQLite fixture_db_open_of_new(); |
||||
|
pEpSQLite fixture_db_open_of_existing_and_verified(); |
||||
|
pEpSQLite fixture_db_open_of_bad(); |
||||
|
pEpSQLite fixture_db_open_of_corrupt(); |
||||
|
pEpSQLite fixture_db_open_after_close(); |
||||
|
// tables
|
||||
|
pEpSQLite fixture_db_open_with_tables_of_new(); |
||||
|
// content
|
||||
|
pEpSQLite fixture_db_open_with_tables_and_content(); |
||||
|
// delete
|
||||
|
pEpSQLite fixture_db_open_after_delete(); |
||||
|
pEpSQLite fixture_db_open_after_close_after_delete(); |
||||
|
|
||||
|
|
||||
|
// TESTS
|
||||
|
// -----
|
||||
|
// instance creation
|
||||
|
pEpSQLite test_create_instance_on_new(); // OK
|
||||
|
pEpSQLite test_create_instance_on_existing(); // OK
|
||||
|
pEpSQLite test_create_instance_on_path_bad(); // OK
|
||||
|
pEpSQLite test_create_instance_on_path_corrupt(); // OK
|
||||
|
// db create_open (create_or_open())
|
||||
|
pEpSQLite test_createopen_db_new(); // OK, new db
|
||||
|
pEpSQLite test_createopen_db_existing(); // OK, open db
|
||||
|
pEpSQLite test_createopen_db_bad(); // ERR, cant create
|
||||
|
pEpSQLite test_createopen_db_corrupt(); // OK (cant detect corruption)
|
||||
|
// close()
|
||||
|
pEpSQLite test_close_before_open(); // OK
|
||||
|
pEpSQLite test_close_after_open(); // OK
|
||||
|
pEpSQLite test_close_idempotent(); // OK
|
||||
|
// create tables (execute())
|
||||
|
pEpSQLite test_db_create_tables_on_open_new(); // OK
|
||||
|
pEpSQLite test_db_create_tables_open_existing(); // ERR, Tables already exist
|
||||
|
pEpSQLite test_db_create_tables_on_open_bad(); // ERR, db closed
|
||||
|
pEpSQLite test_db_create_tables_on_open_corrupt(); // ERR, db corrupt
|
||||
|
// insert (execute())
|
||||
|
pEpSQLite test_db_insert_on_tables_exist(); // OK
|
||||
|
pEpSQLite test_db_insert_on_tables_dont_exist(); // ERR, Tables missing
|
||||
|
pEpSQLite test_db_insert_before_open(); // ERR, Tables missing
|
||||
|
pEpSQLite test_db_insert_after_close(); // ERR, Tables missing
|
||||
|
// verify contents (execute())
|
||||
|
pEpSQLite test_db_verify_content_existing_open_db(); // OK
|
||||
|
pEpSQLite test_db_verify_content_after_insert_on_tables_exist(); // OK
|
||||
|
pEpSQLite test_db_verify_content_no_tables(); // ERR - no tables
|
||||
|
pEpSQLite test_db_verify_content_after_create_tables(); // ERR - err no data
|
||||
|
// get_path()
|
||||
|
pEpSQLite test_get_path_on_instance_good(); // OK
|
||||
|
pEpSQLite test_get_path_on_instance_bad(); // OK
|
||||
|
// delete_db()
|
||||
|
pEpSQLite test_delete_file_gone_before_open_new(); // OK?
|
||||
|
pEpSQLite test_delete_file_gone_before_open_existing(); // OK
|
||||
|
pEpSQLite test_delete_file_gone_after_close_new(); // OK
|
||||
|
pEpSQLite test_delete_file_gone_after_open_existing(); // OK
|
||||
|
pEpSQLite test_delete_file_gone_after_open_corrupt(); // OK
|
||||
|
pEpSQLite test_delete_file_gone_after_open_bad(); // ERR
|
||||
|
// is_open()
|
||||
|
pEpSQLite test_is_open_before_open_new(); // false
|
||||
|
pEpSQLite test_is_open_after_open_new(); // true
|
||||
|
pEpSQLite test_is_open_after_open_existing(); // true
|
||||
|
pEpSQLite test_is_open_after_open_bad(); // false
|
||||
|
pEpSQLite test_is_open_after_open_corrupt(); // true (cant detect corruption)
|
||||
|
pEpSQLite test_is_open_after_close(); // false
|
||||
|
pEpSQLite test_is_open_after_delete_on_open(); // false
|
||||
|
pEpSQLite test_is_open_after_delete_on_closed(); // false
|
||||
|
|
||||
|
} // namespace Test
|
||||
|
} // end of namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_TEST_PEPSQLITE_HH
|
@ -0,0 +1,492 @@ |
|||||
|
#include "pitytest11/src/PityTest.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
// libpEpAdapter
|
||||
|
#include "../src/Adapter.hh" |
||||
|
#include "../src/group_manager_api.h" |
||||
|
#include "../src/pEpLog.hh" |
||||
|
#include "../src/status_to_string.hh" |
||||
|
#include "../src/grp_driver_replicator.hh" |
||||
|
|
||||
|
// engine
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/mime.h> |
||||
|
|
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::Test::Utils; |
||||
|
using namespace pEp::PityTest11; |
||||
|
using namespace pEp::Adapter::pEpLog; |
||||
|
|
||||
|
|
||||
|
using TextContext = PityPerspective; |
||||
|
using TestUnitSwarm = PityUnit<TextContext>; |
||||
|
|
||||
|
|
||||
|
TextContext *local_ctx; |
||||
|
PityUnit<TextContext> *local_pity; |
||||
|
|
||||
|
// Either group manager or group member, not both
|
||||
|
pEpIdent group_ident; |
||||
|
|
||||
|
bool grp_did_tx_encrypted = false; |
||||
|
bool grp_did_rx_encrypted = false; |
||||
|
bool signal_received = false; |
||||
|
// The most minimal received msg contains of:
|
||||
|
// * from address
|
||||
|
// * content
|
||||
|
using MinMsgRx = std::tuple<std::string, std::string>; |
||||
|
|
||||
|
// CALLBACKS
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
::PEP_STATUS test_messageToSend(::message *_msg) |
||||
|
{ |
||||
|
local_pity->log("MESSAGE TO SEND:" + Utils::to_string(_msg, false)); |
||||
|
std::string mime_text = mimeEncode(wrap(_msg)); |
||||
|
local_pity->transport()->sendMsg(_msg->to->ident->address, mime_text); |
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
::PEP_STATUS test_notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, sync_handshake_signal signal) |
||||
|
{ |
||||
|
local_pity->log("NOTFY_HANDSHAKE: signal: " + std::string(std::to_string(signal))); |
||||
|
local_pity->log("NOTFY_HANDSHAKE: me:" + Utils::to_string(me, false)); |
||||
|
local_pity->log("NOTFY_HANDSHAKE: partner: " + Utils::to_string(partner, false)); |
||||
|
if (signal == ::SYNC_NOTIFY_GROUP_INVITATION) { |
||||
|
signal_received = true; |
||||
|
group_ident = dup(me); |
||||
|
local_pity->log("SYNC_NOTIFY_GROUP_INVITATION"); |
||||
|
PEP_STATUS status = ::adapter_group_join( |
||||
|
Adapter::session(), |
||||
|
group_ident.get(), |
||||
|
local_ctx->own_ident.get()); |
||||
|
throw_status(status); |
||||
|
} |
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
// HELPERS
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
// Blocking
|
||||
|
void processMessage() |
||||
|
{ |
||||
|
local_pity->log("waiting for message..."); |
||||
|
std::string mime_data_rx = local_pity->transport()->receiveMsg(); |
||||
|
// local_pity->log("mime_text:" + Utils::clip(mime_data_rx, 300));
|
||||
|
|
||||
|
// Decode
|
||||
|
pEpMessage rx_msg = mimeDecode(mime_data_rx); |
||||
|
// local_pity->log("decode: " + Utils::to_string(rx_msg.get(), false));
|
||||
|
|
||||
|
// Decrypt
|
||||
|
::PEP_decrypt_flags_t flags = ::PEP_decrypt_flag_dont_trigger_sync; |
||||
|
// ::PEP_decrypt_flags_t flags = 0;
|
||||
|
DecryptResult decres = decryptMessage(rx_msg, &flags); |
||||
|
pEpMessage msg_decrypt = std::get<0>(decres); |
||||
|
// local_pity->log("Decrypt: " + Utils::to_string(msg_decrypt.get(), false));
|
||||
|
local_pity->log("message processed..."); |
||||
|
} |
||||
|
|
||||
|
// Non-Blocking
|
||||
|
void processsAllMessages() |
||||
|
{ |
||||
|
while (local_pity->transport()->hasMsg()) { |
||||
|
Utils::sleep_millis(100); |
||||
|
processMessage(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void tofu_send(TestUnitSwarm &pity, TextContext *ctx, const std::string &addr, const std::string longmessage) |
||||
|
{ |
||||
|
pEpMessage msg = createMessage(ctx->own_ident, addr, longmessage); |
||||
|
EncryptResult msg_enc = encryptAndEncode(msg); |
||||
|
std::string mime_text = std::get<1>(msg_enc); |
||||
|
ctx->getPeer(addr)->did_tx_encrypted = std::get<2>(msg_enc); |
||||
|
pity.log("Sending Encrypted[" + std::to_string(std::get<2>(msg_enc)) + "] to: " + addr); |
||||
|
pity.transport()->sendMsg(addr, mime_text); |
||||
|
} |
||||
|
|
||||
|
MinMsgRx tofu_receive(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
MinMsgRx ret; |
||||
|
const std::string mime_data_rx = pity.transport()->receiveMsg(); |
||||
|
|
||||
|
DecryptResult msg_rx = decryptAndDecode(mime_data_rx); |
||||
|
pEpMessage msg_rx_dec = std::get<0>(msg_rx); |
||||
|
ctx->getPeer(msg_rx_dec->from->address)->did_rx_encrypted = std::get<4>(msg_rx); |
||||
|
pity.log( |
||||
|
"Received Encrypted[" + std::to_string(std::get<4>(msg_rx)) + |
||||
|
"] from: " + std::string(msg_rx_dec->from->address)); |
||||
|
// pity.log("IN:\n " + Utils::to_string(mimeDecode(mime_data_rx).get(), false));
|
||||
|
pity.log("DECRYPTED:\n " + Utils::to_string(msg_rx_dec.get(), false)); |
||||
|
std::get<0>(ret) = std::string(msg_rx_dec->from->address); |
||||
|
std::get<1>(ret) = std::string(msg_rx_dec->longmsg); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void tofu_receiveAndReply(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
MinMsgRx rx_msg = tofu_receive(pity, ctx); |
||||
|
|
||||
|
std::string addr = std::get<0>(rx_msg); |
||||
|
std::string longmsg_orig = std::get<1>(rx_msg); |
||||
|
pEpMessage msg = createMessage( |
||||
|
ctx->own_ident, |
||||
|
addr, |
||||
|
"REPLY_FROM:'" + std::string(addr) + "' - " + longmsg_orig); |
||||
|
|
||||
|
tofu_send(pity, ctx, addr, "REPLY_FROM:'" + std::string(addr) + "' - " + longmsg_orig); |
||||
|
} |
||||
|
|
||||
|
// TESTUNITS
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
int test_pEp_init(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
local_ctx = ctx; |
||||
|
local_pity = &pity; |
||||
|
pity.log("Model : " + ctx->model.getName()); |
||||
|
pity.log("myself : " + ctx->own_name); |
||||
|
pity.log("partner: " + ctx->getCpt().addr); |
||||
|
pity.log("HOME : " + std::string(getenv("HOME"))); |
||||
|
pity.log("PUD : " + std::string(::per_user_directory())); |
||||
|
pity.log("PMD : " + std::string(::per_machine_directory())); |
||||
|
pEp::Adapter::session.initialize( |
||||
|
pEp::Adapter::SyncModes::Async, |
||||
|
false, |
||||
|
test_messageToSend, |
||||
|
test_notifyHandshake); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_create_myself(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
// Create new identity
|
||||
|
pity.log("updating or creating identity for me"); |
||||
|
ctx->own_ident = createOwnIdent(ctx->own_name); |
||||
|
::PEP_STATUS status = ::myself(Adapter::session(), ctx->own_ident.get()); |
||||
|
pEp::throw_status(status); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_start_sync(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
Adapter::session |
||||
|
.initialize(Adapter::SyncModes::Async, false, test_messageToSend, test_notifyHandshake); |
||||
|
processsAllMessages(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_tofu_init_all_peers(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
for (auto &peer : ctx->peers) { |
||||
|
tofu_send(pity, ctx, peer.addr, "INIT TOFU"); |
||||
|
tofu_receiveAndReply(pity, ctx); |
||||
|
PITYASSERT(peer.tofu_done(), "TOFU failed for " + peer.addr); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_tofu_react(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
tofu_receiveAndReply(pity, ctx); |
||||
|
tofu_receive(pity, ctx); |
||||
|
// std::cout << pity.getParentProcessUnit().getName() << "GET:" << &ctx->getCpt() << std::endl;
|
||||
|
PITYASSERT(ctx->getCpt().tofu_done(), "TOFU failed for" + ctx->getCpt().addr); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_create(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
if (ctx->groups.size() > 0) { |
||||
|
group_ident = createCptIdent(ctx->groups.front().addr); |
||||
|
PEP_STATUS status = ::adapter_group_create( |
||||
|
Adapter::session(), |
||||
|
group_ident.get(), |
||||
|
ctx->own_ident.get(), |
||||
|
nullptr); |
||||
|
pEp::throw_status(status); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_invite_members(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
PEP_STATUS status; |
||||
|
if (ctx->groups.size() > 0) { |
||||
|
Group &my_grp = ctx->groups.at(0); |
||||
|
auto grp_ident = createRawIdent(my_grp.addr); |
||||
|
status = ::update_identity(Adapter::session(), grp_ident.get()); |
||||
|
throw_status(status); |
||||
|
|
||||
|
pity.log(Utils::to_string(grp_ident.get(), false)); |
||||
|
for (TestIdent mb : my_grp.members) { |
||||
|
auto mb_ident = createRawIdent(mb.addr); |
||||
|
status = ::update_identity(Adapter::session(), mb_ident.get()); |
||||
|
throw_status(status); |
||||
|
pity.log(Utils::to_string(mb_ident.get(), false)); |
||||
|
|
||||
|
status = ::adapter_group_invite_member(Adapter::session(), grp_ident.get(), mb_ident.get()); |
||||
|
throw_status(status); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_join(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
processMessage(); |
||||
|
PITYASSERT(signal_received, "test_group_join - no signal received"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_receive_joined(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
PEP_STATUS status; |
||||
|
if (ctx->groups.size() > 0) { |
||||
|
Group &my_grp = ctx->groups.at(0); |
||||
|
for (TestIdent mb : my_grp.members) { |
||||
|
processMessage(); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int test_send_groupmessage(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
const std::string addr = group_ident->address; |
||||
|
pEpMessage msg = createMessage(ctx->own_ident, addr, "GROUP MESSAGE"); |
||||
|
EncryptResult msg_enc = encryptAndEncode(msg); |
||||
|
std::string mime_text = std::get<1>(msg_enc); |
||||
|
grp_did_tx_encrypted = std::get<2>(msg_enc); |
||||
|
pity.log("Sending to GROUP Encrypted[" + std::to_string(std::get<2>(msg_enc)) + "] to: " + addr); |
||||
|
|
||||
|
// Send to members and moderator (except self)
|
||||
|
for (const auto &member : ctx->getGroup(addr)->members) { |
||||
|
if (member.addr != ctx->own_name) { |
||||
|
pity.log("To: " + member.addr); |
||||
|
pity.transport()->sendMsg(member.addr, mime_text); |
||||
|
} |
||||
|
} |
||||
|
if (ctx->getGroup(addr)->moderator != ctx->own_name) { |
||||
|
pity.log("To: " + ctx->getGroup(addr)->moderator); |
||||
|
pity.transport()->sendMsg(ctx->getGroup(addr)->moderator, mime_text); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int test_receive(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
MinMsgRx ret; |
||||
|
const std::string mime_data_rx = pity.transport()->receiveMsg(); |
||||
|
|
||||
|
DecryptResult msg_rx = decryptAndDecode(mime_data_rx); |
||||
|
pEpMessage msg_rx_dec = std::get<0>(msg_rx); |
||||
|
ctx->getPeer(msg_rx_dec->from->address)->did_rx_encrypted = std::get<4>(msg_rx); |
||||
|
pity.log( |
||||
|
"Received Encrypted[" + std::to_string(std::get<4>(msg_rx)) + |
||||
|
"] from: " + std::string(msg_rx_dec->from->address)); |
||||
|
// pity.log("IN:\n " + Utils::to_string(mimeDecode(mime_data_rx).get(), false));
|
||||
|
// pity.log("DECRYPTED:\n " + Utils::to_string(msg_rx_dec.get(), false));
|
||||
|
std::get<0>(ret) = std::string(msg_rx_dec->from->address); |
||||
|
std::get<1>(ret) = std::string(msg_rx_dec->longmsg); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_receive_all(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
while (local_pity->transport()->hasMsg()) { |
||||
|
Utils::sleep_millis(100); |
||||
|
test_receive(pity, ctx); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_remove_member_one_by_one(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
bool is_empty = false; |
||||
|
do { |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_members(Adapter::session(), group_ident.get(), &idl); |
||||
|
throw_status(status); |
||||
|
pity.log(Utils::to_string(idl, false)); |
||||
|
if (idl->ident != nullptr) { |
||||
|
status = ::adapter_group_remove_member(Adapter::session(), group_ident.get(), idl->ident); |
||||
|
throw_status(status); |
||||
|
} else { |
||||
|
is_empty = true; |
||||
|
} |
||||
|
} while (!is_empty); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_query1(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_groups(Adapter::session(), &idl); |
||||
|
throw_status(status); |
||||
|
pity.log(Utils::to_string(idl, false)); |
||||
|
PITYASSERT(idl->ident == nullptr, "adapter_group_query_groups"); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_query2(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_groups(Adapter::session(), &idl); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(idl, false));
|
||||
|
PITYASSERT(idl->ident->address == ctx->groups.begin()->addr, "adapter_group_query_groups"); |
||||
|
} |
||||
|
{ |
||||
|
pEpIdent mgr = createRawIdent(""); |
||||
|
::pEp_identity *mgr_ptr = mgr.get(); |
||||
|
::PEP_STATUS status = ::adapter_group_query_manager( |
||||
|
Adapter::session(), |
||||
|
group_ident.get(), |
||||
|
&mgr_ptr); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(mgr_ptr, false));
|
||||
|
// pity.log(Utils::to_string(ctx->own_ident.get(), false));
|
||||
|
PITYASSERT( |
||||
|
*mgr_ptr->address == *ctx->own_ident->address, |
||||
|
"adapter_group_query_manager - wrong manager"); |
||||
|
} |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_members(Adapter::session(), group_ident.get(), &idl); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(idl, false));
|
||||
|
PITYASSERT(idl->ident == nullptr, "adapter_group_query_members"); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int test_group_query3(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_groups(Adapter::session(), &idl); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(idl, false));
|
||||
|
PITYASSERT(idl->ident->address == ctx->groups.begin()->addr, "adapter_group_query_groups"); |
||||
|
} |
||||
|
{ |
||||
|
pEpIdent mgr = createRawIdent(""); |
||||
|
::pEp_identity *mgr_ptr = mgr.get(); |
||||
|
::PEP_STATUS status = ::adapter_group_query_manager( |
||||
|
Adapter::session(), |
||||
|
group_ident.get(), |
||||
|
&mgr_ptr); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(mgr_ptr, false));
|
||||
|
// pity.log(Utils::to_string(ctx->own_ident.get(), false));
|
||||
|
PITYASSERT( |
||||
|
*mgr_ptr->address == *ctx->own_ident->address, |
||||
|
"adapter_group_query_manager - wrong manager"); |
||||
|
} |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_members(Adapter::session(), group_ident.get(), &idl); |
||||
|
throw_status(status); |
||||
|
pity.log(Utils::to_string(idl, false)); |
||||
|
// PITYASSERT(idl->ident->address == ctx->getCpt().addr, "adapter_group_query_members");
|
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_group_query4(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_groups(Adapter::session(), &idl); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(idl, false));
|
||||
|
PITYASSERT(idl->ident->address == ctx->groups.begin()->addr, "adapter_group_query_groups"); |
||||
|
} |
||||
|
{ |
||||
|
pEpIdent mgr = createRawIdent(""); |
||||
|
::pEp_identity *mgr_ptr = mgr.get(); |
||||
|
::PEP_STATUS status = ::adapter_group_query_manager( |
||||
|
Adapter::session(), |
||||
|
group_ident.get(), |
||||
|
&mgr_ptr); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(mgr_ptr, false));
|
||||
|
// pity.log(Utils::to_string(ctx->own_ident.get(), false));
|
||||
|
PITYASSERT( |
||||
|
*mgr_ptr->address == *ctx->own_ident->address, |
||||
|
"adapter_group_query_manager - wrong manager"); |
||||
|
} |
||||
|
{ |
||||
|
::identity_list *idl = nullptr; |
||||
|
::PEP_STATUS status = ::adapter_group_query_members(Adapter::session(), group_ident.get(), &idl); |
||||
|
throw_status(status); |
||||
|
// pity.log(Utils::to_string(idl, false));
|
||||
|
// PITYASSERT(idl->ident->address == ctx->getCpt().addr, "adapter_group_query_members");
|
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
// Adapter::pEpLog::set_enabled(true);
|
||||
|
// Adapter::GroupDriverReplicator::log_enabled = true;
|
||||
|
// Adapter::GroupDriverEngine::log_enabled = true;
|
||||
|
// Adapter::GroupDriverDummy::log_enabled = true;
|
||||
|
// TestUnit::debug_log_enabled = false;
|
||||
|
// PityTransport::debug_log_enabled = true;
|
||||
|
int nodesCount = 23; |
||||
|
PityModel model{ "model_tofu2", nodesCount }; |
||||
|
TestUnitSwarm suite = TestUnitSwarm("suite_tofu2"); |
||||
|
PitySwarm swarm{ "swarm_tofu2", model }; |
||||
|
suite.addRef(swarm.getSwarmUnit()); |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_pEp_init", test_pEp_init)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_create_myself", test_create_myself)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_tofu_init_all_peers", test_tofu_init_all_peers)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_start_sync", test_start_sync)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_query1", test_group_query1)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_create", test_group_create)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_query2", test_group_query2)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_invite_members", test_group_invite_members)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_query3", test_group_query3)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_receive_joined", test_receive_joined)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_query3", test_group_query3)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_send_groupmessage", test_send_groupmessage)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_receive", test_receive)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_receive_all", test_receive_all)); |
||||
|
swarm.addTestUnit( |
||||
|
0, |
||||
|
TestUnitSwarm("test_group_remove_member_one_by_one", test_group_remove_member_one_by_one)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_group_query4", test_group_query4)); |
||||
|
|
||||
|
//------------------------------------------------------------------------------------
|
||||
|
for (int i = 1; i < nodesCount; i++) { |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_pEp_init", test_pEp_init)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_create_myself", test_create_myself)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_tofu_react", test_tofu_react)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_start_sync", test_start_sync)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_group_join", test_group_join)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_receive", test_receive)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_send_groupmessage", test_send_groupmessage)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_receive_all", test_receive_all)); |
||||
|
} |
||||
|
|
||||
|
suite.run(); |
||||
|
} |
@ -0,0 +1,135 @@ |
|||||
|
#include "pitytest11/src/PityTest.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
// libpEpAdapter
|
||||
|
#include "../src/Adapter.hh" |
||||
|
#include "../src/group_manager_api.h" |
||||
|
#include "../src/pEpLog.hh" |
||||
|
#include "../src/status_to_string.hh" |
||||
|
#include "../src/grp_driver_replicator.hh" |
||||
|
|
||||
|
// engine
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/mime.h> |
||||
|
|
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::Test::Utils; |
||||
|
using namespace pEp::PityTest11; |
||||
|
using namespace pEp::Adapter::pEpLog; |
||||
|
|
||||
|
using TextContext = PityPerspective; |
||||
|
using TestUnitSwarm = PityUnit<TextContext>; |
||||
|
|
||||
|
TextContext *local_ctx; |
||||
|
PityUnit<TextContext> *local_pity; |
||||
|
|
||||
|
// The most minimal received msg contains of:
|
||||
|
// * from address
|
||||
|
// * content
|
||||
|
using MinMsgRx = std::tuple<std::string, std::string>; |
||||
|
|
||||
|
void tofu_send(TestUnitSwarm &pity, TextContext *ctx, const std::string &addr, const std::string longmessage) |
||||
|
{ |
||||
|
pEpMessage msg = createMessage(ctx->own_ident, addr, longmessage); |
||||
|
EncryptResult msg_enc = encryptAndEncode(msg); |
||||
|
|
||||
|
std::string mime_text = std::get<1>(msg_enc); |
||||
|
ctx->getPeer(addr)->did_tx_encrypted = std::get<2>(msg_enc); |
||||
|
pity.log("Sending Encrypted[" + std::to_string(std::get<2>(msg_enc)) + "] to: " + addr); |
||||
|
pity.transport()->sendMsg(addr, mime_text); |
||||
|
} |
||||
|
|
||||
|
MinMsgRx tofu_receive(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
MinMsgRx ret; |
||||
|
const std::string mime_data_rx = pity.transport()->receiveMsg(); |
||||
|
|
||||
|
DecryptResult msg_rx = decryptAndDecode(mime_data_rx); |
||||
|
pEpMessage msg_rx_dec = std::get<0>(msg_rx); |
||||
|
ctx->getPeer(msg_rx_dec->from->address)->did_rx_encrypted = std::get<4>(msg_rx); |
||||
|
pity.log( |
||||
|
"Received Encrypted[" + std::to_string(std::get<4>(msg_rx)) + |
||||
|
"] from: " + std::string(msg_rx_dec->from->address)); |
||||
|
// pity.log("IN:\n " + Utils::to_string(mimeDecode(mime_data_rx).get(), false));
|
||||
|
pity.log("DECRYPTED:\n " + Utils::to_string(msg_rx_dec.get(), false)); |
||||
|
std::get<0>(ret) = std::string(msg_rx_dec->from->address); |
||||
|
std::get<1>(ret) = std::string(msg_rx_dec->longmsg); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void tofu_receiveAndReply(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
MinMsgRx rx_msg = tofu_receive(pity, ctx); |
||||
|
|
||||
|
std::string addr = std::get<0>(rx_msg); |
||||
|
std::string longmsg_orig = std::get<1>(rx_msg); |
||||
|
pEpMessage msg = createMessage( |
||||
|
ctx->own_ident, |
||||
|
addr, |
||||
|
"REPLY_FROM:'" + std::string(addr) + "' - " + longmsg_orig); |
||||
|
|
||||
|
tofu_send(pity, ctx, addr, "REPLY_FROM:'" + std::string(addr) + "' - " + longmsg_orig); |
||||
|
} |
||||
|
|
||||
|
// TESTUNITS
|
||||
|
// ------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
int test_create_myself(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
Adapter::session.initialize(); |
||||
|
// Create new identity
|
||||
|
pity.log("updating or creating identity for me"); |
||||
|
ctx->own_ident = createOwnIdent(ctx->own_name); |
||||
|
::PEP_STATUS status = ::myself(Adapter::session(), ctx->own_ident.get()); |
||||
|
pEp::throw_status(status); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_tofu_init_all_peers(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
for (auto &peer : ctx->peers) { |
||||
|
tofu_send(pity, ctx, peer.addr, "INIT TOFU"); |
||||
|
tofu_receiveAndReply(pity, ctx); |
||||
|
PITYASSERT(peer.tofu_done(), "TOFU failed for " + peer.addr); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_tofu_react(TestUnitSwarm &pity, TextContext *ctx) |
||||
|
{ |
||||
|
tofu_receiveAndReply(pity, ctx); |
||||
|
tofu_receive(pity, ctx); |
||||
|
PITYASSERT(ctx->getCpt().tofu_done(), "TOFU failed for" + ctx->getCpt().addr); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
// Adapter::pEpLog::set_enabled(true);
|
||||
|
// Adapter::GroupDriverReplicator::log_enabled = true;
|
||||
|
// Adapter::GroupDriverEngine::log_enabled = true;
|
||||
|
// Adapter::GroupDriverDummy::log_enabled = true;
|
||||
|
// TestUnit::debug_log_enabled = false;
|
||||
|
// PityTransport::debug_log_enabled = true;
|
||||
|
int nodesCount = 23; |
||||
|
PityModel model{ "model_tofu2", nodesCount }; |
||||
|
TestUnitSwarm suite = TestUnitSwarm("suite_tofu2"); |
||||
|
PitySwarm swarm{ "swarm_tofu2", model }; |
||||
|
suite.addRef(swarm.getSwarmUnit()); |
||||
|
// ------------------------------------------------------------------------------------
|
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_create_myself", test_create_myself)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("test_tofu_init_all_peers", test_tofu_init_all_peers)); |
||||
|
|
||||
|
for (int i = 1; i < nodesCount; i++) { |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_create_myself", test_create_myself)); |
||||
|
swarm.addTestUnit(i, TestUnitSwarm("test_tofu_react", test_tofu_react)); |
||||
|
} |
||||
|
suite.run(); |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
#include <iostream> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/sync_api.h> |
||||
|
|
||||
|
#include "../src/Adapter.hh" |
||||
|
|
||||
|
using namespace pEp; |
||||
|
|
||||
|
PEP_STATUS messageToSend(struct _message *msg) |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, ::sync_handshake_signal signal) |
||||
|
{ |
||||
|
TESTLOG("called"); |
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char **argv) |
||||
|
{ |
||||
|
pEp::Test::setup(argc, argv); |
||||
|
Adapter::session.initialize(Adapter::SyncModes::Async, false); |
||||
|
// Create new identity
|
||||
|
TESTLOG("updating or creating identity for me"); |
||||
|
::pEp_identity *me = ::new_identity("alice@peptest.ch", NULL, "23", "Who the F* is Alice"); |
||||
|
assert(me); |
||||
|
::PEP_STATUS status = ::myself(Adapter::session(), me); |
||||
|
::free_identity(me); |
||||
|
throw_status(status); |
||||
|
|
||||
|
// start and stop sync repeatedly
|
||||
|
unsigned long long int nrIters = 1000 * 1000 * 1000; |
||||
|
for (int i = 0; i < nrIters; i++) { |
||||
|
TESTLOG("RUN NR: "); |
||||
|
TESTLOG(i); |
||||
|
TESTLOG("SYNC START"); |
||||
|
TESTLOG("starting the adapter including sync"); |
||||
|
Adapter::start_sync(); |
||||
|
TESTLOG("SYNC STOP"); |
||||
|
Utils::sleep_millis(500); |
||||
|
Adapter::stop_sync(); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
#include "pitytest11/src/PityTest.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/Adapter.hh> |
||||
|
#include <pEp/status_to_string.hh> |
||||
|
#include <pEp/mime.h> |
||||
|
|
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::Test::Utils; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
// Test template for 3 nodes (processes) running the same 2 tests each in their own environment in parallel
|
||||
|
using TestUnitSwarm = PityUnit<PityPerspective>; |
||||
|
|
||||
|
// This is the 1st test unit
|
||||
|
int test_func1(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
pity.log(ctx->own_name); |
||||
|
pity.log("getName: " + pity.getName()); |
||||
|
pity.log("getPath: " + pity.getPath()); |
||||
|
pity.log("getPathShort: " + pity.getPathShort()); |
||||
|
pity.log("getTransportDir: " + pity.getTransportDir()); |
||||
|
pity.log("getProcessDir: " + pity.getProcessDir()); |
||||
|
pity.log("getGlobalRootDir: " + pity.getGlobalRootDir()); |
||||
|
pity.log("to_string: " + pity.to_string()); |
||||
|
|
||||
|
PITYASSERT(true, ""); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// This is the 2nd test unit
|
||||
|
int test_func2(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
pity.log(ctx->own_name); |
||||
|
PITYASSERT(false, ""); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
int nodecount = 3; |
||||
|
PityModel model{ "templ_swarm_multi", nodecount }; |
||||
|
PitySwarm swarm{ "swarm_multi", model }; |
||||
|
|
||||
|
// 1. Create the swarm process TestUnit
|
||||
|
// 2. Append a PityUnit to process 1 unit
|
||||
|
swarm.addTestUnit(0, TestUnitSwarm("unit1", test_func1)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("unit1_1", test_func2)); |
||||
|
|
||||
|
swarm.addTestUnit(1, TestUnitSwarm("unit2", test_func1)); |
||||
|
swarm.addTestUnit(1, TestUnitSwarm("unit2_1", test_func2)); |
||||
|
|
||||
|
swarm.addTestUnit(2, TestUnitSwarm("unit3", test_func1)); |
||||
|
swarm.addTestUnit(2, TestUnitSwarm("unit3_1", test_func2)); |
||||
|
|
||||
|
swarm.run(); |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
#include "pitytest11/src/PityTest.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/Adapter.hh> |
||||
|
#include <pEp/status_to_string.hh> |
||||
|
#include <pEp/mime.h> |
||||
|
|
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::Test::Utils; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
using TestUnitSwarm = PityUnit<PityPerspective>; |
||||
|
// Test template for a single process with 2 test units that run in sequence
|
||||
|
|
||||
|
// This is the 1st test unit
|
||||
|
int test_func1(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
// here some example values from the PityUnit
|
||||
|
pity.log("getName: " + pity.getName()); |
||||
|
pity.log("getPath: " + pity.getPath()); |
||||
|
pity.log("getPathShort: " + pity.getPathShort()); |
||||
|
pity.log("getTransportDir: " + pity.getTransportDir()); |
||||
|
pity.log("getProcessDir: " + pity.getProcessDir()); |
||||
|
pity.log("getGlobalRootDir: " + pity.getGlobalRootDir()); |
||||
|
pity.log("to_string: " + pity.to_string(false)); |
||||
|
PITYASSERT(true, ""); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// This is the 2nd test unit
|
||||
|
int test_func2(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
pity.log(ctx->own_name); |
||||
|
PITYASSERT(false, ""); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
PityModel model{ "templ_swarm_single", 1 }; |
||||
|
PitySwarm swarm{ "swarm_single", model }; |
||||
|
|
||||
|
swarm.addTestUnit(0, TestUnitSwarm("unit1", test_func1)); |
||||
|
swarm.addTestUnit(0, TestUnitSwarm("unit1_1", test_func2)); |
||||
|
|
||||
|
swarm.run(); |
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
#include "pitytest11/src/PityTest.hh" |
||||
|
#include "../src/utils.hh" |
||||
|
#include "framework/framework.hh" |
||||
|
#include "framework/utils.hh" |
||||
|
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/Adapter.hh> |
||||
|
#include <pEp/status_to_string.hh> |
||||
|
|
||||
|
using namespace pEp; |
||||
|
using namespace pEp::Adapter; |
||||
|
using namespace pEp::Test::Utils; |
||||
|
using namespace pEp::PityTest11; |
||||
|
|
||||
|
using TestUnitSwarm = PityUnit<PityPerspective>; |
||||
|
|
||||
|
|
||||
|
bool did_tx_encrypted = false; |
||||
|
bool did_rx_encrypted = false; |
||||
|
|
||||
|
// The most minimal received msg contains of:
|
||||
|
// * from addres
|
||||
|
// * content
|
||||
|
using MinMsgRx = std::tuple<std::string, std::string>; |
||||
|
|
||||
|
void send(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
// Create Message
|
||||
|
pity.log("Initiating TOFU..."); |
||||
|
pEpMessage msg = createMessage(ctx->own_ident, ctx->getCpt().addr, "INIT TOFU"); |
||||
|
pity.log("BEFORE encrypt: \n" + Utils::to_string(msg.get())); |
||||
|
|
||||
|
//Encrypt
|
||||
|
EncryptResult msg_encrypted = encryptMessage(msg); |
||||
|
did_tx_encrypted = std::get<2>(msg_encrypted); |
||||
|
pity.log("TX COULD ENCRYPT: " + std::to_string(did_tx_encrypted)); |
||||
|
pity.log("AFTER encrypt: \n" + Utils::to_string(std::get<0>(msg_encrypted).get())); |
||||
|
|
||||
|
// Encode
|
||||
|
std::string mime_text = mimeEncode(std::get<0>(msg_encrypted)); |
||||
|
|
||||
|
// Send
|
||||
|
pity.transport()->sendMsg(ctx->getCpt().addr, mime_text); |
||||
|
} |
||||
|
|
||||
|
MinMsgRx tofu_receive(PityUnit<PityPerspective> &pity, PityPerspective *ctx) |
||||
|
{ |
||||
|
MinMsgRx ret; |
||||
|
// Receive
|
||||
|
std::string mime_data_rx = pity.transport()->receiveMsg(); |
||||
|
|
||||
|
// Decode
|
||||
|
pEpMessage mime_decoded = mimeDecode(mime_data_rx); |
||||
|
pity.log("RX message - BEFORE decrypt: \n" + Utils::to_string(mime_decoded.get())); |
||||
|
|
||||
|
// Decrypt
|
||||
|
DecryptResult msg_decrypted = decryptMessage(mime_decoded); |
||||
|
pEpMessage msg_rx_dec = std::get<0>(msg_decrypted); |
||||
|
did_rx_encrypted = std::get<4>(msg_decrypted); |
||||
|
pity.log("RX WAS ENCRYPTED: " + std::to_string(did_rx_encrypted)); |
||||
|
pity.log("RX message - AFTER decrypt: \n" + Utils::to_string(msg_rx_dec.get())); |
||||
|
|
||||
|
// Return result
|
||||
|
std::get<0>(ret) = std::string(msg_rx_dec->from->address); |
||||
|
std::get<1>(ret) = std::string(msg_rx_dec->longmsg); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void receiveAndReply(PityUnit<PityPerspective> &pity, PityPerspective *ctx, MinMsgRx msg_orig) |
||||
|
{ |
||||
|
// Create Message
|
||||
|
std::string addr_orig = std::get<0>(msg_orig); |
||||
|
std::string longmsg_orig = std::get<1>(msg_orig); |
||||
|
|
||||
|
pEpMessage msg = createMessage( |
||||
|
ctx->own_ident, |
||||
|
addr_orig, |
||||
|
"REPLY[ " + std::string(addr_orig) + " ] " + longmsg_orig); |
||||
|
|
||||
|
// Encrypt
|
||||
|
pity.log("TX message - BEFORE encrypt: \n" + Utils::to_string(msg.get())); |
||||
|
|
||||
|
EncryptResult eres = encryptMessage(msg); |
||||
|
pEpMessage msg_encrypted = std::get<0>(eres); |
||||
|
did_tx_encrypted = std::get<2>(eres); |
||||
|
pity.log("TX COULD ENCRYPT: " + std::to_string(did_tx_encrypted)); |
||||
|
pity.log("TX message - AFTER encrypt: \n" + Utils::to_string(msg_encrypted.get())); |
||||
|
|
||||
|
// Encode
|
||||
|
std::string mime_data_tx = mimeEncode(msg_encrypted); |
||||
|
|
||||
|
// Send
|
||||
|
pity.transport()->sendMsg(addr_orig, mime_data_tx); |
||||
|
} |
||||
|
|
||||
|
int tofu(PityUnit<PityPerspective> &pity, PityPerspective *ctx, bool init) |
||||
|
{ |
||||
|
pity.log("Model : " + ctx->model.getName()); |
||||
|
pity.log("myself : " + ctx->own_name); |
||||
|
pity.log("partner: " + ctx->getCpt().addr); |
||||
|
pity.log("HOME : " + std::string(getenv("HOME"))); |
||||
|
pity.log("PUD : " + std::string(::per_user_directory())); |
||||
|
Adapter::session.initialize(); |
||||
|
|
||||
|
// Create new identity
|
||||
|
pity.log("updating or creating identity for me"); |
||||
|
ctx->own_ident = createOwnIdent(ctx->own_name); |
||||
|
::PEP_STATUS status = ::myself(Adapter::session(), ctx->own_ident.get()); |
||||
|
pEp::throw_status(status); |
||||
|
if (init) { |
||||
|
send(pity, ctx); |
||||
|
} |
||||
|
|
||||
|
MinMsgRx rx_msg = tofu_receive(pity, ctx); |
||||
|
receiveAndReply(pity, ctx, rx_msg); |
||||
|
|
||||
|
if (!init) { |
||||
|
tofu_receive(pity, ctx); |
||||
|
} |
||||
|
|
||||
|
PITYASSERT(did_tx_encrypted, "could never tofu_send encrypted"); |
||||
|
PITYASSERT(did_rx_encrypted, "no encrypted msg received"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
PityUnit<PityPerspective>::debug_log_enabled = false; |
||||
|
|
||||
|
int nodesCount = 2; |
||||
|
PityModel model{ "test_tofu_react", nodesCount }; |
||||
|
|
||||
|
TestUnitSwarm suite("suite_tofu"); |
||||
|
PitySwarm swarm{ "swarm_tofu", model }; |
||||
|
suite.addRef(swarm.getSwarmUnit()); |
||||
|
|
||||
|
swarm.addTestUnit( |
||||
|
0, |
||||
|
TestUnitSwarm("tofu1", [](PityUnit<PityPerspective> &unit, PityPerspective *ctx) { |
||||
|
return tofu(unit, ctx, true); |
||||
|
})); |
||||
|
|
||||
|
swarm.addTestUnit( |
||||
|
1, |
||||
|
TestUnitSwarm("tofu2", [](PityUnit<PityPerspective> &unit, PityPerspective *ctx) { |
||||
|
return tofu(unit, ctx, false); |
||||
|
})); |
||||
|
|
||||
|
suite.run(); |
||||
|
} |
Loading…
Reference in new issue