diff --git a/Makefile b/Makefile index de77d7d..0b7f68e 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,12 @@ src-debug: test: src-debug $(MAKE) -C test + $(MAKE) -C test-suite clean: $(MAKE) -C src clean $(MAKE) -C test clean + $(MAKE) -C test-suite clean install: $(MAKE) -C src install diff --git a/Makefile.conf b/Makefile.conf index 5f4b365..e67a3b8 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -30,15 +30,25 @@ CFLAGS+=-std=c17 -fPIC # Constants CFLAGS+=-I$(PREFIX)/include -LDFLAGS+=-L$(PREFIX)/lib - CFLAGS+=-I$(SYS_PREFIX)/include +CFLAGS+=-fPIC -pthread -DSQLITE_THREADSAFE=1 +LDFLAGS+=-L$(PREFIX)/lib LDFLAGS+=-L$(SYS_PREFIX)/lib +CXXFLAGS+=-std=c++11 -fPIC +CXXFLAGS+=-Wall -pedantic-errors -Wno-unused-parameter -Wno-reorder-ctor +CXXFLAGS+=-isystem $(PREFIX)/include + ifneq (,$(findstring g++,$(CC))) CFLAGS+=-fdiagnostics-color=always else ifneq (,$(findstring clang,$(CC))) CFLAGS+=-fcolor-diagnostics endif - +ifeq ($(DEBUG),1) + CXXFLAGS+=-g -O0 + CFLAGS+=-g -O0 +else + CXXFLAGS+=-DNDEBUG=1 -O3 + CFLAGS+=-DNDEBUG=1 -O3 +endif diff --git a/src/pEpTransportUDP.h b/src/pEpTransportUDP.h index d3e2cee..3240b49 100644 --- a/src/pEpTransportUDP.h +++ b/src/pEpTransportUDP.h @@ -1,6 +1,10 @@ #ifndef PEPUDPTRANSPORT_H #define PEPUDPTRANSPORT_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include #include @@ -53,4 +57,7 @@ signal_incoming_message_t cb_incoming_message; bool allCallbacksRegistered(); +#ifdef __cplusplus +} +#endif #endif // PEPUDPTRANSPORT_H diff --git a/test-suite/Makefile b/test-suite/Makefile new file mode 100644 index 0000000..e0c6cfd --- /dev/null +++ b/test-suite/Makefile @@ -0,0 +1,30 @@ +include ../Makefile.conf + +LDFLAGS:=-L../src $(LDFLAGS) +LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter -lpEpCxx11 -lPityTest11 -lpthread -ldl -lm -lpEpTransportUDP +CXXFLAGS:=-I../src -I$(PREFIX)/include $(CXXFLAGS) -Wc++11-extensions + +# Test +SRC_TEST=$(wildcard test_*.cc) +BIN_TEST=$(subst .cc,,$(SRC_TEST)) + +# Framework +SRC_FRAMEWORK=$(wildcard framework/*.cc) +OBJ_FRAMEWORK=$(subst .cc,.o,$(SRC_FRAMEWORK)) + +.PHONY: all clean +.DEFAULT_GOAL := all + +all: $(BIN_TEST) + +$(BIN_TEST): $(OBJ_FRAMEWORK) + +clean: + rm -f $(BIN_TEST) + rm -f $(OBJ_FRAMEWORK) + rm -Rf *.dSYM + rm -f *.d + rm -f *.o + rm -rf pitytest_data/ + + diff --git a/test-suite/framework/framework.cc b/test-suite/framework/framework.cc new file mode 100644 index 0000000..f69dec2 --- /dev/null +++ b/test-suite/framework/framework.cc @@ -0,0 +1,208 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +pEp::Test::Transport pEp::Test::transport; + +using namespace pEp; + +namespace pEp { + namespace Test { + std::string per_user_dir{}; + std::string resource_dir{}; + + void setup(std::vector &args) + { + std::string dir{}; + resource_dir = Utils::path_get_abs("resource/"); +#ifdef WIN32 + dir = getenv("TEMP"); + dir += "\\test_pEp.XXXXXXXXXXXX"; +#endif + + if (args.size() > 1) { + if (args[1] == "--help") { +#ifdef WIN32 + std::cout << "usage: " << args[0] << " [--dir LOCALAPPDATA]" << std::endl; +#else + std::cout << "usage: " << args[0] << " [--dir HOME]" << std::endl; +#endif + exit(0); + } else if (args[1] == "--dir" && args.size() == 3) { + dir = args[2]; + } else { + std::cerr << "illegal parameter" << std::endl; + exit(1); + } + } + +#ifdef WIN32 + char _path[MAXPATHLEN + 1]; + const char *templ = dir.c_str(); + strcpy(_path, templ); + mkdtemp(_path); + chdir(_path); + setenv("LOCALAPPDATA", _path, 1); + per_user_dir = _path; +#else + dir = Utils::path_get_abs("testdata"); + Utils::dir_recreate(dir); + setenv("HOME", dir.c_str(), 1); + Utils::dir_set_cwd(dir); + pEpLog("$HOME set to:" + dir); + per_user_dir = dir; +#endif + + std::cerr << "test directory: " << per_user_dir << std::endl; + } + + void setup(int argc, char **argv) + { + std::vector args{ (size_t)argc }; + for (int i = 0; i < argc; ++i) { + args[i] = argv[i]; + } + + setup(args); + } + + std::string get_resource_abs(const std::string &name) + { + return Utils::path_get_abs(resource_dir + name); + } + + void import_key_from_file(const std::string &filename) + { + std::string key = Utils::file_read(filename); + // ifstream f(filename, ifstream::in); + // string key{ istreambuf_iterator(f), istreambuf_iterator() }; + ::identity_list *il = nullptr; + std::cout << key.c_str() << std::endl; + std::cout << key.length() << std::endl; + ::PEP_STATUS status = ::import_key(Adapter::session(), key.c_str(), key.length(), &il); + throw_status(status); + assert(status == PEP_KEY_IMPORTED); + ::free_identity_list(il); + } + + Message make_message(::message *msg) + { + return std::shared_ptr<::message>(msg, ::free_message); + } + + Identity make_identity(::pEp_identity *ident) + { + return std::shared_ptr<::pEp_identity>(ident, ::free_identity); + } + + Message mime_parse(std::string text) + { + ::message *msg = nullptr; + bool has_possible_pEp_msg = false; + ::PEP_STATUS status = ::mime_decode_message( + text.c_str(), + text.length(), + &msg, + &has_possible_pEp_msg); + throw_status(status); + return make_message(msg); + } + + std::string mime_compose(Message msg) + { + char *mimetext = nullptr; + PEP_STATUS status = ::mime_encode_message(msg.get(), false, &mimetext, false); + throw_status(status); + std::string text = mimetext; + free(mimetext); + return text; + } + + std::string make_pEp_msg(Message msg) + { + std::string text; + + ::message *_dst = nullptr; + stringlist_t *keylist = nullptr; + ::PEP_rating rating{}; + ::PEP_decrypt_flags_t flags = 0; + ::PEP_STATUS status = ::decrypt_message( + Adapter::session(), + msg.get(), + &_dst, + &keylist, + &rating, + &flags); + throw_status(status); + + Message dst; + if (_dst) { + dst = make_message(_dst); + } else { + dst = msg; + } + + if (dst.get()->attachments) { + for (auto a = dst.get()->attachments; a && a->value; a = a->next) { + if (std::string("application/pEp.sync") == a->mime_type) { + char *_text; + status = ::PER_to_XER_Sync_msg(a->value, a->size, &_text); + throw_status(status); + text += _text; + ::pEp_free(_text); + return text; + } else if (std::string("application/pEp.distribution") == a->mime_type) { + char *_text; + status = ::PER_to_XER_Distribution_msg(a->value, a->size, &_text); + throw_status(status); + text += _text; + ::pEp_free(_text); + return text; + } + } + } + + return text; + } + + void join_sync_thread() + { + if (Adapter::_sync_thread.joinable()) { + Adapter::_sync_thread.join(); + } + } + + Message Transport::recv() + { + mkdir(inbox_path.c_str(), 0770); + auto msg = make_message(nullptr); + + return msg; + } + + void Transport::send(Message msg) + { + mkdir(outbox_path.c_str(), 0770); + } + } // namespace Test +} // namespace pEp diff --git a/test-suite/framework/framework.hh b/test-suite/framework/framework.hh new file mode 100644 index 0000000..622660b --- /dev/null +++ b/test-suite/framework/framework.hh @@ -0,0 +1,64 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#ifndef LIBPEPADAPTER_FRAMEWORK_HH +#define LIBPEPADAPTER_FRAMEWORK_HH + +#include +#include +#include + +#include + +namespace pEp { + namespace Test { + // manually set up test + void setup(std::vector &args); + + // call this in main() for auto set up + void setup(int argc = 1, char **argv = nullptr); + + std::string get_resource_abs(const std::string &name); + + void import_key_from_file(const std::string& filename); + + using Message = std::shared_ptr<::message>; + using Identity = std::shared_ptr<::pEp_identity>; + + // use this instead of constructor to auto assign ::free_message as + // deleter + Message make_message(::message *msg); + + // use this instead of constructor to auto assign ::free_identity as + // deleter + Identity make_identity(::pEp_identity *ident); + + // MIME parser + Message mime_parse(std::string text); + + // MIME composer + std::string mime_compose(Message msg); + + // Sync and Distribution decoder + std::string make_pEp_msg(Message msg); + + // wait until Sync has shut down + void join_sync_thread(); + + struct Transport { + std::string inbox_path = "inbox"; + std::string outbox_path = "outbox"; + + // reads next message from inbox + Message recv(); + + // appends message to outbox + void send(Message msg); + }; + + extern Transport transport; + extern std::string per_user_dir; + } // namespace Test +} // namespace pEp + +#endif // LIBPEPADAPTER_FRAMEWORK_HH diff --git a/test-suite/hide/test_adapter_cxx.cc b/test-suite/hide/test_adapter_cxx.cc new file mode 100644 index 0000000..f917ba5 --- /dev/null +++ b/test-suite/hide/test_adapter_cxx.cc @@ -0,0 +1,70 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" +#include +#include +#include +#include + +#include +#include + +#include "../src/Adapter.hh" + +namespace Utils = pEp::Utils; +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; +} + +class JNISync { +public: + void onSyncStartup() + { + TESTLOG("called"); + } + + void onSyncShutdown() + { + TESTLOG("called"); + } +} o; + +int main(int argc, char *argv[]) +{ + Test::setup(argc, argv); + pEp::Adapter::session + .initialize(pEp::Adapter::SyncModes::Async, false, messageToSend, notifyHandshake); + // 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 = 3; + for (int i = 0; i < nrIters; i++) { + TESTLOG("RUN NR: "); + TESTLOG(i); + TESTLOG("SYNC START"); + TESTLOG("starting the adapter including sync"); + Adapter::startup(&o, &JNISync::onSyncStartup, &JNISync::onSyncShutdown); + Utils::sleep_millis(2000); + TESTLOG("SYNC STOP"); + Adapter::stop_sync(); + Utils::sleep_millis(2000); + } + return 0; +} \ No newline at end of file diff --git a/test-suite/hide/test_ensure_passphrase.cc b/test-suite/hide/test_ensure_passphrase.cc new file mode 100644 index 0000000..ef36d11 --- /dev/null +++ b/test-suite/hide/test_ensure_passphrase.cc @@ -0,0 +1,51 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" + +#include +#include +#include + +#include "../src/passphrase_cache.hh" +#include "../src/Adapter.hh" + +using namespace pEp; +using namespace std; + +int main(int argc, char** argv) +{ + pEp::Adapter::pEpLog::set_enabled(true); + Test::setup(argc, argv); + Adapter::session.initialize(); + passphrase_cache.add("erwin"); + passphrase_cache.add("cathy"); + passphrase_cache.add("bob"); + + std::string bob_filename = Test::get_resource_abs("bob-primary-with-password-bob-subkey-without.pgp"); + std::string bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736"; + + std::string erwin_filename = Test::get_resource_abs("erwin_normal_encrypted.pgp"); + std::string erwin_fpr = "CBA968BC01FCEB89F04CCF155C5E9E3F0420A570"; + + Test::import_key_from_file(bob_filename); + Test::import_key_from_file(erwin_filename); + + ::pEp_identity* bob = ::new_identity("bob@example.org", bob_fpr.c_str(), "BOB", "Bob Dog"); + ::PEP_STATUS status = ::set_own_key(Adapter::session(), bob, bob_fpr.c_str()); + assert(status == PEP_STATUS_OK); + + ::pEp_identity* erwin = ::new_identity("erwin@example.org", erwin_fpr.c_str(), "BOB", "Bob is Erwin"); + status = ::set_own_key(Adapter::session(), erwin, erwin_fpr.c_str()); + assert(status == PEP_STATUS_OK); + + status = ::key_reset_all_own_keys(Adapter::session()); + assert(status == PEP_STATUS_OK); + + ::free_identity(bob); + ::free_identity(erwin); + + // session(Adapter::release); + + return 0; +} diff --git a/test-suite/hide/test_group.cc b/test-suite/hide/test_group.cc new file mode 100644 index 0000000..7e733f7 --- /dev/null +++ b/test-suite/hide/test_group.cc @@ -0,0 +1,254 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" +#include + +//#include + +#include "../src/Adapter.hh" +#include "../src/utils.hh" +#include + +#include "../src/grp_manager_interface.hh" +#include "../src/grp_driver_engine.hh" +#include "../src/grp_driver_dummy.hh" +#include "../src/grp_driver_replicator.hh" + +//#include "../src/adapter_group.h" +#include "../src/status_to_string.hh" + +#include +#include + +using namespace std; +using namespace pEp; +using namespace pEp::Adapter; +using namespace pEp::Adapter::pEpLog; + +bool debug_info_full = true; + + +// Model +const string lmd_path = "test.db"; +::pEp_identity* alice = nullptr; +::pEp_identity* bob = nullptr; +::pEp_identity* carol = nullptr; +::pEp_identity* grp_ident = nullptr; +::PEP_STATUS status; + + +string dummy_in; + + +GroupUpdateInterface* gu = nullptr; +GroupQueryInterface* gq = nullptr; + +/* + * Callbacks + */ + +::PEP_STATUS test_messageToSend(::message* _msg) +{ + log("called"); + log(Test::make_pEp_msg(Test::make_message(_msg))); + return PEP_STATUS_OK; +} + +::PEP_STATUS test_notifyHandshake(::pEp_identity* _me, ::pEp_identity* _partner, sync_handshake_signal signal) +{ + log("called"); + log("me: " + pEp::Utils::to_string(_me, false)); + log("partner: " + pEp::Utils::to_string(_partner, false)); + log("Signal: " + to_string(signal)); + // log("Signal: " + string{ ::sync_handshake_signal_to_string(signal) }); + + return PEP_STATUS_OK; +} + +/* + * Test Units + */ + +void test_create_alice_me() +{ + logH2("test_create_alice_me"); + alice = ::new_identity("alice@peptest.ch", NULL, "23", "Alice"); + assert(alice); + alice->lang[0] = 'e'; + alice->lang[1] = 'n'; + status = ::myself(Adapter::session(), alice); + log("STATUS: " + status_to_string(status)); + assert(!status); + log("Alice:" + pEp::Utils::to_string(alice, debug_info_full)); +} + +void test_create_bob_partner() +{ + logH2("test_create_bob_partner"); + bob = ::new_identity("bob@peptest.ch", NULL, PEP_OWN_USERID, "Bob"); + assert(bob); + // bob->lang[0] = 'c'; + // bob->lang[1] = 'r'; + // status = ::myself(Adapter::session(), bob); + status = ::update_identity(Adapter::session(), bob); + log("STATUS: " + status_to_string(status)); + assert(!status); + log("Bob:" + pEp::Utils::to_string(bob, debug_info_full)); +} + +void test_create_carol_partner() +{ + logH2("test_create_carol_partner"); + carol = ::new_identity("carol@peptest.ch", NULL, PEP_OWN_USERID, "Carol"); + assert(carol); + carol->lang[0] = 'f'; + carol->lang[1] = 'n'; + status = ::update_identity(Adapter::session(), carol); + // status = ::myself(Adapter::session(), carol); + log("STATUS: " + status_to_string(status)); + assert(!status); + log("Carol:" + pEp::Utils::to_string(carol, debug_info_full)); +} + +void test_setup_and_start_sync() +{ + logH2("test_setup_and_start_sync"); + Adapter::start_sync(); +} + +void test_group_create() +{ + logH2("test_group_create"); + ::identity_list* initial_memberlist = nullptr; + initial_memberlist = new_identity_list(bob); + ::identity_list_add(initial_memberlist, carol); + + log("create group identity"); + grp_ident = ::new_identity("group1@peptest.ch", NULL, "432", "group1"); + assert(grp_ident); + log("grp_ident:" + pEp::Utils::to_string(grp_ident, debug_info_full)); + + // PEP_STATUS stat = ::myself(Adapter::session(), grp_ident); + // log("STATUS: " + status_to_string(status)); + // assert(stat == PEP_STATUS_OK); + // log("grp_ident:" + pEp::Utils::to_string(grp_ident, debug_info_full)); + + log("adapter_group_create()"); + status = gu->adapter_group_create(Adapter::session(), grp_ident, alice, nullptr); + log("STATUS: " + status_to_string(status)); + assert(!status); +} + +void test_group_invite_member(::pEp_identity& ident) +{ + logH2("test_group_invite_member"); + assert(grp_ident); + status = gu->adapter_group_invite_member(Adapter::session(), grp_ident, &ident); + log("STATUS: " + status_to_string(status)); + assert(!status); +} + +void test_group_remove_member(::pEp_identity& ident) +{ + logH2("test_group_remove_member"); + status = gu->adapter_group_remove_member(Adapter::session(), grp_ident, &ident); + log("STATUS: " + status_to_string(status)); + assert(!status); +} + +void test_group_dissolve() +{ + logH2("test_group_dissolve"); + status = gu->adapter_group_dissolve(Adapter::session(), grp_ident, alice); + log("STATUS: " + status_to_string(status)); + assert(!status); +} + +/* + * Update functions + * ---------------- + * Test procedure: + * 1. Create group + * - group_create(Alice) + * 2. Add Bob + * - group_invite_member(Bob) +// * - group_join(Bob) + * 3. Add Carol + * - group_invite_member(Carol) +// * - group_join(Carol) + * 4. Remove Carol + * - group_remove_member(Carol) +// * 5. Rating +// * - group_rating() (Just test once, to see it is generally working) + * 6. Dissolve + * - group_dissolve() + * + * Query functions + * --------------- + * Always test all the query functions for correctness between every step above. + * group_query_groups() + * group_query_manager() + * group_query_members + */ + + +int main(int argc, char** argv) +{ + Test::setup(argc, argv); + Adapter::pEpLog::set_enabled(false); + debug_info_full = true; + + // pEpSQLite::log_enabled = true; + // ListManagerDummy::log_enabled = true; + GroupDriverDummy::log_enabled = true; + GroupDriverEngine::log_enabled = true; + GroupDriverReplicator::log_enabled = true; + + + GroupDriverDummy gdd{ lmd_path }; + GroupDriverEngine gde{}; + GroupDriverReplicator gdr{}; + + + gu = &gde; + gq = nullptr; + + // gu = &gdd; + // gq = &gdd; + + // gu = &gdr; + // gq = &gdr; + Adapter::session.initialize(); + + // Setup Test Context + test_create_alice_me(); + test_create_bob_partner(); + test_create_carol_partner(); + + test_setup_and_start_sync(); + + logH1("1. Create group"); + + test_group_create(); + logH1("2. Add Bob"); + test_group_invite_member(*bob); // Fails + logH1("3. Add Carol"); + test_group_invite_member(*carol); + logH1("4. Remove Carol"); + test_group_remove_member(*carol); + + if (gq != nullptr) { + ::pEp_identity* grp_ident = ::new_identity("group1@peptest.ch", NULL, "432", "group1"); + ::pEp_identity* manager = nullptr; + PEP_STATUS stat = gq->group_query_manager(Adapter::session(), grp_ident, &manager); + log(status_to_string(stat)); + log(::Utils::to_string(manager)); + } + logH1("6. Dissolve"); + test_group_dissolve(); + + + Adapter::stop_sync(); + return 0; +} diff --git a/test-suite/hide/test_leave_device_group.cc b/test-suite/hide/test_leave_device_group.cc new file mode 100644 index 0000000..bbc3903 --- /dev/null +++ b/test-suite/hide/test_leave_device_group.cc @@ -0,0 +1,124 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" + +#include +#include + +#include + +#include "../src/callback_dispatcher.hh" +#include "../src/Adapter.hh" +#include "../src/passphrase_cache.hh" + +using namespace std; +using namespace pEp; + +vector expected_msg = { "synchronizeGroupKeys", + "groupKeysUpdate", + "initUnledGroupKeyReset", + "beacon", + "beacon" }; + +vector<::sync_handshake_signal> expected_notification = { SYNC_NOTIFY_IN_GROUP, + SYNC_NOTIFY_START, + SYNC_NOTIFY_SOLE, + SYNC_NOTIFY_START, + SYNC_NOTIFY_STOP }; + +::PEP_STATUS test_messageToSend(::message* _msg) +{ + + static auto actual = expected_msg.begin(); + Test::Message msg = Test::make_message(_msg); + string text = Test::make_pEp_msg(msg); + cerr << "expecting: " << *actual << endl; + cerr << text; + assert(text.find(*actual++) != string::npos); + return PEP_STATUS_OK; +} + + +::PEP_STATUS test_notifyHandshake(::pEp_identity* _me, ::pEp_identity* _partner, sync_handshake_signal signal) +{ + static auto actual = expected_notification.begin(); + + Test::Identity me = Test::make_identity(_me); + Test::Identity partner = Test::make_identity(_partner); + cerr << "expecting: " << *actual << endl; + cerr << "notifyHandshake: " << signal << endl; + assert(signal == *actual++); + return PEP_STATUS_OK; +} + +int main(int argc, char** argv) +{ + pEp::Adapter::pEpLog::set_enabled(true); + Test::setup(argc, argv); + pEpLog(getenv("HOME")); + int n; + std::cin >> n; + Adapter::session.initialize(Adapter::SyncModes::Async, false); + + // set up two own identites for sync + passphrase_cache.add("erwin"); + passphrase_cache.add("bob"); + + std::string bob_filename = Test::get_resource_abs( + "bob-primary-with-password-bob-subkey-without.pgp"); + std::string bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736"; + + std::string erwin_filename = Test::get_resource_abs("erwin_normal_encrypted.pgp"); + std::string erwin_fpr = "CBA968BC01FCEB89F04CCF155C5E9E3F0420A570"; + + Test::import_key_from_file(bob_filename); + Test::import_key_from_file(erwin_filename); + + Test::Identity bob = Test::make_identity( + ::new_identity("bob@example.org", bob_fpr.c_str(), "BOB", "Bob Dog")); + PEP_STATUS status = ::set_own_key(Adapter::session(), bob.get(), bob_fpr.c_str()); + assert(status == PEP_STATUS_OK); + + status = ::enable_identity_for_sync(Adapter::session(), bob.get()); + assert(status == PEP_STATUS_OK); + + Test::Identity erwin = Test::make_identity( + ::new_identity("erwin@example.org", erwin_fpr.c_str(), "BOB", "Bob is Erwin")); + status = ::set_own_key(Adapter::session(), erwin.get(), erwin_fpr.c_str()); + assert(status == PEP_STATUS_OK); + + status = ::enable_identity_for_sync(Adapter::session(), erwin.get()); + assert(status == PEP_STATUS_OK); + + // simulate a device group by setting the identities to in sync + + status = ::set_identity_flags(Adapter::session(), bob.get(), PEP_idf_devicegroup); + status = ::set_identity_flags(Adapter::session(), erwin.get(), PEP_idf_devicegroup); + + // register at callback_dispatcher and start sync + + callback_dispatcher.add(test_messageToSend, test_notifyHandshake); + Adapter::start_sync(); + + // leave device group + status = ::leave_device_group(Adapter::session()); + throw_status(status); + // wait for sync shutdown and release first session + + Test::join_sync_thread(); + assert(!Adapter::is_sync_running()); + + // switch off and on again + + Adapter::start_sync(); + sleep(2); + assert(Adapter::is_sync_running()); + Adapter::stop_sync(); + Test::join_sync_thread(); + assert(!Adapter::is_sync_running()); + + Adapter::session.release(); + + return 0; +} diff --git a/test-suite/hide/test_listmanager_dummy.cc b/test-suite/hide/test_listmanager_dummy.cc new file mode 100644 index 0000000..b286e15 --- /dev/null +++ b/test-suite/hide/test_listmanager_dummy.cc @@ -0,0 +1,307 @@ +#include "../src/listmanager_dummy.hh" +#include "../src/utils.hh" +#include +#include +#include +#include + + +using namespace std; +using namespace pEp; +using namespace pEp::Adapter::pEpLog; +using namespace pEp::Utils; + +struct lm_list { + string addr; + string mod; + vector members; +}; + +struct model_test_lmd { + string alice; + string bob; + string carol; + string joe; + string db_path; + vector lists; + vector lists_addr() const + { + vector 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"); +} \ No newline at end of file diff --git a/test-suite/hide/test_message_cache.cc b/test-suite/hide/test_message_cache.cc new file mode 100644 index 0000000..005af71 --- /dev/null +++ b/test-suite/hide/test_message_cache.cc @@ -0,0 +1,125 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" + +#include +#include +#include +#include +#include + +#include "../src/message_cache.hh" +#include "../src/Adapter.hh" + +using namespace std; +using namespace pEp; + +int main(int argc, char **argv) +{ + Test::setup(argc, argv); + Adapter::session.initialize(); + + ::pEp_identity *alice = ::new_identity("alice@mail.com", nullptr, PEP_OWN_USERID, "Alice"); + ::myself(Adapter::session(), alice); + + char *mime = strdup("From: Alice \n" + "To: Bob \n" + "Subject: short message\n" + "\n" + "long message\n"); + + // add to cache + + ::message *src = nullptr; + bool has_possible_pEp_msg; + ::PEP_STATUS status = MessageCache::cache_mime_decode_message( + mime, + strlen(mime), + &src, + &has_possible_pEp_msg); + assert(status == PEP_STATUS_OK); + + status = ::myself(Adapter::session(), src->from); + assert(status == PEP_STATUS_OK); + + ::update_identity(Adapter::session(), src->to->ident); + assert(status == PEP_STATUS_OK); + + ::pEp_identity *bob = identity_dup(src->to->ident); + + src->dir = ::PEP_dir_outgoing; + ::message *dst = nullptr; + cout << "cache_encrypt_message()" << endl; + status = MessageCache::cache_encrypt_message( + Adapter::session(), + src, + nullptr, + &dst, + PEP_enc_PEP, + 0); + assert(status != PEP_ILLEGAL_VALUE); + + assert(src->longmsg == nullptr); + assert(src->attachments == nullptr); + + assert(dst == nullptr); + + // remove from cache + + free(mime); + mime = nullptr; + status = MessageCache::cache_mime_encode_message(MessageCache::msg_src, src, false, &mime, false); + assert(status == PEP_STATUS_OK); + cout << "cache_mime_encode_message()" << endl; + cout << "mime: " << endl << mime << endl; + + // add to cache + + ::free_message(src); + src = nullptr; + cout << "cache_mime_decode_message" << endl; + status = MessageCache::cache_mime_decode_message(mime, strlen(mime), &src, &has_possible_pEp_msg); + assert(status == PEP_STATUS_OK); + + assert(src->longmsg == nullptr); + assert(src->attachments == nullptr); + + ::PEP_rating rating; + ::PEP_decrypt_flags_t flags = 0; + ::stringlist_t *keylist = nullptr; + + cout << "cache_decrypt_message" << endl; + status = MessageCache::cache_decrypt_message( + Adapter::session(), + src, + &dst, + &keylist, + &rating, + &flags); + assert(status != PEP_ILLEGAL_VALUE); + + assert(src->longmsg == nullptr); + assert(src->attachments == nullptr); + + // remove from cache + + free(mime); + mime = nullptr; + cout << "cache_mime_encode_message" << endl; + status = MessageCache::cache_mime_encode_message(MessageCache::msg_src, src, false, &mime, false); + + assert(src->longmsg == nullptr); + assert(src->attachments == nullptr); + + cout << "mime: " << endl << mime << endl; + + free(mime); + ::free_message(src); + ::free_message(dst); + ::free_identity(bob); + ::free_identity(alice); + + Adapter::session.release(); + return 0; +} diff --git a/test-suite/hide/test_pEpSQLite.cc b/test-suite/hide/test_pEpSQLite.cc new file mode 100644 index 0000000..90bad20 --- /dev/null +++ b/test-suite/hide/test_pEpSQLite.cc @@ -0,0 +1,642 @@ +#include "test_pEpSQLite.hh" +#include "../src/pEpSQLite.hh" +#include "../src/utils.hh" +#include +#include + +#include +#include + +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; +} \ No newline at end of file diff --git a/test-suite/hide/test_pEpSQLite.hh b/test-suite/hide/test_pEpSQLite.hh new file mode 100644 index 0000000..87665a3 --- /dev/null +++ b/test-suite/hide/test_pEpSQLite.hh @@ -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 +#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 diff --git a/test-suite/hide/test_passphrase_cache.cc b/test-suite/hide/test_passphrase_cache.cc new file mode 100644 index 0000000..ace0fed --- /dev/null +++ b/test-suite/hide/test_passphrase_cache.cc @@ -0,0 +1,101 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" + +#include +#include +#include + +#include "../src/passphrase_cache.hh" +#include "../src/status_to_string.hh" +#include "../src/Adapter.hh" + +using namespace pEp; + +extern "C" { +::PEP_STATUS api_test1(::PEP_SESSION session, const char *str, char *bytes, int n, ::stringlist_t *sl) +{ + std::cout << "called api_test1\n"; + return PEP_WRONG_PASSPHRASE; +} + +::PEP_STATUS api_test2(::PEP_SESSION session, int n, const char *str, char *bytes, ::stringlist_t *sl) +{ + std::cout << "called api_test2\n"; + return PEP_STATUS_OK; +} +}; + +int main(int argc, char **argv) +{ + Test::setup(argc, argv); + Adapter::session.initialize(); + const char *str = "23"; + char *bytes = NULL; + int n = 42; + ::stringlist_t *sl = NULL; + + PassphraseCache cache{ 2, std::chrono::seconds(1) }; + cache.add("say"); + cache.add("hello"); + cache.add("world"); + + std::cout << "expected: two passphrases\n"; + cache.for_each_passphrase([&](std::string passphrase) { + std::cout << "'" << passphrase << "'\n"; + return false; + }); + + std::cout << "expected: one passphrase\n"; + cache.for_each_passphrase([&](std::string passphrase) { + std::cout << "'" << passphrase << "'\n"; + return passphrase != ""; + }); + + std::cout << "expected: two passphrases but reverse order\n"; + cache.for_each_passphrase([&](std::string passphrase) { + std::cout << "'" << passphrase << "'\n"; + return false; + }); + + ::PEP_STATUS status = cache.api(api_test1, Adapter::session(), "23", bytes, n, (::stringlist_t *)NULL); + assert(status == PEP_WRONG_PASSPHRASE); + status = cache.api(api_test2, Adapter::session(), n, str, bytes, sl); + assert(status == PEP_STATUS_OK); + + cache.add("hello"); + cache.add("world"); + std::cout << "expected: two passphrases in reverse order\n"; + PassphraseCache _cache = cache; + try { + while (1) { + std::cout << "'" << _cache.latest_passphrase(_cache) << "'\n"; + } + } catch (std::underflow_error &) { + } + + passphrase_cache.add("hello"); + passphrase_cache.add("world"); + std::cout << "two times PEP_STATUS_OK (0), one time PEP_WRONG_PASSPHRASE (2561)\n"; + do { + status = PassphraseCache::config_next_passphrase(); + std::cout << status_to_string(status) << " (" << status << ")\n"; + } while (status == PEP_STATUS_OK); + + sleep(2); + + std::cout << "expected: no passphrase\n"; + cache.for_each_passphrase([&](std::string passphrase) { + std::cout << "'" << passphrase << "'\n"; + return false; + }); + + status = cache.api(api_test1, Adapter::session(), str, bytes, n, sl); + assert(status == PEP_WRONG_PASSPHRASE); + status = cache.api(api_test2, Adapter::session(), 23, str, bytes, sl); + assert(status == PEP_STATUS_OK); + + Adapter::session.release(); + return 0; +} diff --git a/test-suite/hide/test_swarm_group.cc b/test-suite/hide/test_swarm_group.cc new file mode 100644 index 0000000..9413a65 --- /dev/null +++ b/test-suite/hide/test_swarm_group.cc @@ -0,0 +1,492 @@ +#include +#include "../src/utils.hh" +#include "framework/framework.hh" +#include + +// libpEpAdapter +#include "../src/Adapter.hh" +#include "../src/group_manager_api.h" +#include +#include "../src/status_to_string.hh" +#include "../src/grp_driver_replicator.hh" + +// engine +#include +#include +#include +#include +#include + +using namespace pEp; +using namespace pEp::Adapter; +using namespace pEp::Test::Utils; +using namespace pEp::PityTest11; +using namespace pEp::Adapter::pEpLog; + + +using TestContext = PityPerspective; +using TestUnitSwarm = PityUnit; + + +TestContext *local_ctx; +PityUnit *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; + +// 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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *ctx) +{ + Adapter::session + .initialize(Adapter::SyncModes::Async, false, test_messageToSend, test_notifyHandshake); + processsAllMessages(); + return 0; +} + +int test_tofu_init_all_peers(TestUnitSwarm &pity, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *ctx) +{ + processMessage(); + PITYASSERT(signal_received, "test_group_join - no signal received"); + return 0; +} + +int test_receive_joined(TestUnitSwarm &pity, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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(); +} diff --git a/test-suite/hide/test_swarm_tofu.cc b/test-suite/hide/test_swarm_tofu.cc new file mode 100644 index 0000000..72d26ba --- /dev/null +++ b/test-suite/hide/test_swarm_tofu.cc @@ -0,0 +1,134 @@ +#include +#include "../src/utils.hh" +#include "framework/framework.hh" +#include + +// libpEpAdapter +#include "../src/Adapter.hh" +#include "../src/group_manager_api.h" +#include +#include "../src/status_to_string.hh" +#include "../src/grp_driver_replicator.hh" + +// engine +#include +#include +#include +#include +#include + +using namespace pEp; +using namespace pEp::Adapter; +using namespace pEp::Test::Utils; +using namespace pEp::PityTest11; +using namespace pEp::Adapter::pEpLog; + +using TestContext = PityPerspective; +using TestUnitSwarm = PityUnit; + +TestContext *local_ctx; +PityUnit *local_pity; + +// The most minimal received msg contains of: +// * from address +// * content +using MinMsgRx = std::tuple; + +void tofu_send(TestUnitSwarm &pity, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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, TestContext *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(); +} diff --git a/test-suite/hide/test_sync_init.cc b/test-suite/hide/test_sync_init.cc new file mode 100644 index 0000000..a374a13 --- /dev/null +++ b/test-suite/hide/test_sync_init.cc @@ -0,0 +1,53 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" +#include +#include +#include + +#include +#include + +#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; +} diff --git a/test-suite/hide/test_template_swarm_multi.cc b/test-suite/hide/test_template_swarm_multi.cc new file mode 100644 index 0000000..d9494ab --- /dev/null +++ b/test-suite/hide/test_template_swarm_multi.cc @@ -0,0 +1,65 @@ +#include +#include "../src/utils.hh" +#include "framework/framework.hh" +#include + +#include +#include +#include +#include +#include +#include +#include + +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; + +// This is the 1st test unit +int test_func1(PityUnit &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 &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(); +} \ No newline at end of file diff --git a/test-suite/hide/test_template_swarm_single.cc b/test-suite/hide/test_template_swarm_single.cc new file mode 100644 index 0000000..7a41e34 --- /dev/null +++ b/test-suite/hide/test_template_swarm_single.cc @@ -0,0 +1,55 @@ +#include +#include "../src/utils.hh" +#include "framework/framework.hh" +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace pEp; +using namespace pEp::Adapter; +using namespace pEp::Test::Utils; +using namespace pEp::PityTest11; + +using TestUnitSwarm = PityUnit; +// Test template for a single process with 2 test units that run in sequence + +// This is the 1st test unit +int test_func1(PityUnit &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 &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(); +} \ No newline at end of file diff --git a/test-suite/hide/test_tofu.cc b/test-suite/hide/test_tofu.cc new file mode 100644 index 0000000..39fbeee --- /dev/null +++ b/test-suite/hide/test_tofu.cc @@ -0,0 +1,152 @@ +#include +#include "../src/utils.hh" +#include "framework/framework.hh" +#include + +#include +#include +#include +#include + +using namespace pEp; +using namespace pEp::Adapter; +using namespace pEp::Test::Utils; +using namespace pEp::PityTest11; + +using TestUnitSwarm = PityUnit; + + +bool did_tx_encrypted = false; +bool did_rx_encrypted = false; + +// The most minimal received msg contains of: +// * from addres +// * content +using MinMsgRx = std::tuple; + +void send(PityUnit &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 &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 &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 &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::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 &unit, PityPerspective *ctx) { + return tofu(unit, ctx, true); + })); + + swarm.addTestUnit( + 1, + TestUnitSwarm("tofu2", [](PityUnit &unit, PityPerspective *ctx) { + return tofu(unit, ctx, false); + })); + + suite.run(); +} \ No newline at end of file diff --git a/test-suite/resource/bob-primary-with-password-bob-subkey-without.pgp b/test-suite/resource/bob-primary-with-password-bob-subkey-without.pgp new file mode 100644 index 0000000..c2a3c91 Binary files /dev/null and b/test-suite/resource/bob-primary-with-password-bob-subkey-without.pgp differ diff --git a/test-suite/resource/erwin_normal_encrypted.pgp b/test-suite/resource/erwin_normal_encrypted.pgp new file mode 100644 index 0000000..5c4af94 --- /dev/null +++ b/test-suite/resource/erwin_normal_encrypted.pgp @@ -0,0 +1,30 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: CBA9 68BC 01FC EB89 F04C CF15 5C5E 9E3F 0420 A570 +Comment: erwin2-electric-boogaloo@example.org + +xYYEXyRZVBYJKwYBBAHaRw8BAQdAyWxnUgFCgukUn3n98AKyVEM1/zFEbXK29yRj +OJHBG1H+CQMI1MVsl/YGGq7/WC9ZYFQty5jz0X/zo/JY1jFmXqCWCGeMhqLl3WBq +DwGonZVBWhp8QnIXiydHIkqxhxoc7XShHme5hZs28LPIT5LF8EO3vcKHBB8WCgAY +BYJfJFlUBYkFpI+1AgsJAhUKApsBAh4BACEJEFxenj8EIKVwFiEEy6lovAH864nw +TM8VXF6ePwQgpXAlOwEAlOsjerl/1bBhCcO0A3wucwmgUhcnQfRG+WIifKnmhOcA +/20v/GvkgO22K8YZhygwmcSOvx0s93EBxyWRRnG9Pb8IzSRlcndpbjItZWxlY3Ry +aWMtYm9vZ2Fsb29AZXhhbXBsZS5vcmfCigQTFgoAGwWCXyRZVAWJBaSPtQILCQIV +CgKZAQKbAQIeAQAhCRBcXp4/BCClcBYhBMupaLwB/OuJ8EzPFVxenj8EIKVwhQYB +APh7AVFMZ+KCcz5yHn+czAHC9tl8iw3liikqujNqnw8pAQDWlsOMixGS7gYPgDwh +PxYV0y32iFcycHT+0nkDVN50B8eGBF8kWVQWCSsGAQQB2kcPAQEHQHEP9EAwlT1V +nS22ZNOBauv4Exo7aVZKPIknM0PhrIo1/gkDCAJNdcr6xM35/wlyhLfBuX47t+FV +G/dxDWvlHvhL0d10kDRxV2OUOTs9FF6SHhoNmJCTXECgjfIE2VA9Jdwi7kGbFjcL +vZBt9opkoqZsHJjCwDgEGBYKABIFgl8kWVQFiQWkj7UCmwICHgEAmAkQXF6ePwQg +pXB2oAQZFgoABgWCXyRZVAAhCRAOQ+rSK33mEhYhBKs6FrQlWp++ddYFNw5D6tIr +feYSAIABAL+R7weg/XPynY6A5VLLFq5papoAo+UKGMfA5ddK1nJNAP0bN61ikyvN +GVhxivR6+Bjf91a45aYNz/ewllIeEBaMBBYhBMupaLwB/OuJ8EzPFVxenj8EIKVw +cqkA/2Qfrv2dJ6VDDrCC9ucrW4NcMQllNse8GIWKehXp35f9AQD3Vj2qJIve+v9/ +BVnJcREBxT+WFJIa8762bbAEC4XdCMeLBF8kWVQSCisGAQQBl1UBBQEBB0AKCbEf +OOdH80jxLLh9LG3K5hHI9zvo9strgGGAEcaFKwMBCAn+CQMICjFkzCai4CX/NIVi +Vv36MrODVyIK478sFI1Nn7nJpRQynAGRss5LqfmFgEfWlVseBFcC7+o5rmXrG/0/ +Zy4YzHnhWmI/VG9jRSSr6ELGUcKBBBgWCgASBYJfJFlUBYkFpI+1ApsMAh4BACEJ +EFxenj8EIKVwFiEEy6lovAH864nwTM8VXF6ePwQgpXATJQEA/KVMdqzMeug6bQlc +JEX+eh0vpANB3dPIjPem43yTMtQA/0/6GddNBVIH2c2LDEA1ntHsbBWrtL9KG694 +R6OBpcAD +=1aYf +-----END PGP PRIVATE KEY BLOCK----- diff --git a/test-suite/test_adapter b/test-suite/test_adapter new file mode 100755 index 0000000..265dc7c Binary files /dev/null and b/test-suite/test_adapter differ diff --git a/test-suite/test_adapter.cc b/test-suite/test_adapter.cc new file mode 100644 index 0000000..f40f196 --- /dev/null +++ b/test-suite/test_adapter.cc @@ -0,0 +1,62 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "framework/framework.hh" +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../src/pEpTransportUDP.h" + +using namespace std; +using namespace pEp; + +PEP_STATUS messageToSend(struct _message *msg) +{ + TESTLOG("called()"); + ::PEP_transport_status_code tsc; + udp_sendto(Adapter::session(), msg, &tsc); + 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) +{ + Test::setup(argc, argv); + Adapter::pEpLog::set_enabled(true); + + Adapter::session.initialize(Adapter::SyncModes::Async, false, messageToSend, notifyHandshake); + // 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); + pEp::throw_status(status); + + // start and stop sync repeatedly + useconds_t sleepuSec = 1000 * 100; + 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::startup(); + TESTLOG("SYNC STOP"); + usleep(sleepuSec); + Adapter::stop_sync(); + } + return 0; +}