From: Chris Koeritz Date: Thu, 24 Oct 2013 02:13:25 +0000 (-0500) Subject: getting these octopus tests updated. not quite there yet. X-Git-Tag: 2.140.90~899 X-Git-Url: https://feistymeow.org/gitweb/?p=feisty_meow.git;a=commitdiff_plain;h=aad83c15eb10a34baff9b6472f88d1dfa1db9d77 getting these octopus tests updated. not quite there yet. --- diff --git a/octopi/library/makefile b/octopi/library/makefile index 67b1a329..29af249d 100644 --- a/octopi/library/makefile +++ b/octopi/library/makefile @@ -6,7 +6,9 @@ BUILD_BEFORE = octopus \ tentacles \ cromp \ synchronic \ - tests_sockets + tests_sockets + +# tests_octopus include rules.def diff --git a/octopi/library/tests_octopus/makefile b/octopi/library/tests_octopus/makefile new file mode 100755 index 00000000..6784c3bd --- /dev/null +++ b/octopi/library/tests_octopus/makefile @@ -0,0 +1,15 @@ +CONSOLE_MODE = t + +include cpp/variables.def + +PROJECT = tests_octopus +TYPE = test +TARGETS = t_bin.exe t_bin_threaded.exe t_entity.exe t_identity.exe \ + t_security.exe t_unpacker.exe t_file_transfer.exe +LOCAL_LIBS_USED = tentacles octopus sockets unit_test application configuration loggers \ + textual timely processes filesystem structures basis +VCPP_USE_SOCK = t +RUN_TARGETS = $(ACTUAL_TARGETS) + +include cpp/rules.def + diff --git a/octopi/library/tests_octopus/t_bin.cpp b/octopi/library/tests_octopus/t_bin.cpp new file mode 100644 index 00000000..6cbadd35 --- /dev/null +++ b/octopi/library/tests_octopus/t_bin.cpp @@ -0,0 +1,187 @@ +/*****************************************************************************\ +* * +* Name : entity_data_bin tester * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Checks that the entity_data_bin class is behaving as expected. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace application; +using namespace basis; +using namespace loggers; +using namespace octopi; +using namespace textual; + +const int ITEM_COUNT = 10000; + // the number of times to repeat each test operation. + +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger().get(), astring(s)) +#define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger().get(), astring(s)) + +class test_bin : public application_shell +{ +public: + test_bin() : application_shell() {} + DEFINE_CLASS_NAME("test_bin"); + int execute(); +}; + +////////////// + +int test_bin::execute() +{ + FUNCDEF("execute"); + char c = '\0'; + + array item_list; + + entity_data_bin *bing = new entity_data_bin(10 * MEGABYTE); + + enum test_types { ANY = 1, ENT, ID }; + + for (int q = ANY; q <= ID; q++) { +LOG(a_sprintf("test type %d beginning...%c", q, c)); + // using c just shuts up warnings. +//LOG("note memory usage and hit a key:"); +//c = getchar(); + + program_wide_logger().get().eol(parser_bits::NO_ENDING); + for (int i = 1; i <= ITEM_COUNT; i++) { + // test the basic filling of the values in an entity. + octopus_request_id req_id; + int sequencer = randomizer().inclusive(1, MAXINT32 - 10); + int add_in = randomizer().inclusive(0, MAXINT32 - 10); + int process_id = randomizer().inclusive(0, MAXINT32 - 10); + req_id._entity = octopus_entity(string_manipulation::make_random_name(), + process_id, sequencer, add_in); + req_id._request_num = randomizer().inclusive(1, MAXINT32 - 10); + infoton *torp = new security_infoton; + bing->add_item(torp, req_id); + item_list += req_id; + + if (! (i % 50) ) { + printf("^"); + fflush(NIL); + } + } + program_wide_logger().get().eol(parser_bits::CRLF_AT_END); + LOG(""); + + int items_seen = 0; + + program_wide_logger().get().eol(parser_bits::NO_ENDING); + if (q == ANY) { + while (item_list.length()) { + octopus_request_id id; + infoton *found = bing->acquire_for_any(id); + if (!found) + deadly_error(class_name(), "ANY", "item was missing"); + WHACK(found); + items_seen++; + if (! (items_seen % 50) ) { + printf("v"); + fflush(NIL); + } + bool saw_it = false; + for (int q = 0; q < item_list.length(); q++) { + if (item_list[q] == id) { + saw_it = true; + item_list.zap(q, q); + break; + } + } + if (!saw_it) + deadly_error(class_name(), "ANY", "didn't see id for the item"); + } + } else if (q == ENT) { + while (item_list.length()) { + octopus_request_id id; + infoton *found = bing->acquire_for_entity(item_list[0]._entity, id); + if (!found) + deadly_error(class_name(), "ENT", "item was missing"); + WHACK(found); + items_seen++; + if (! (items_seen % 50) ) { + printf("v"); + fflush(NIL); + } + bool saw_it = false; + for (int q = 0; q < item_list.length(); q++) { + if (item_list[q] == id) { + saw_it = true; + item_list.zap(q, q); + break; + } + } + if (!saw_it) + deadly_error(class_name(), "ENT", "didn't see id for the item"); + } + } else if (q == ID) { + for (int j = 0; j < item_list.length(); j++) { + infoton *found = bing->acquire_for_identifier(item_list[j]); + if (!found) + deadly_error(class_name(), "ENT", "item was missing"); + WHACK(found); + items_seen++; + if (! (items_seen % 50) ) { + printf("v"); + fflush(NIL); + } + item_list.zap(j, j); + j--; // skip back. + } + } else { + deadly_error(class_name(), "looping", "bad enum value"); + } + program_wide_logger().get().eol(parser_bits::CRLF_AT_END); + LOG(""); + item_list.reset(); + item_list.shrink(); + + if (bing->entities()) + deadly_error(class_name(), "check left", "there are still contents in table!"); + + bing->clean_out_deadwood(); + +LOG(a_sprintf("test type %d ending...", q)); +//LOG("note memory usage and hit a key:"); +//c = getchar(); + } + + WHACK(bing); +LOG("done testing, zapped bin, now should be low memory."); +//c = getchar(); + + LOG("octopus_entity:: works for those functions tested."); + return 0; +} + +HOOPLE_MAIN(test_bin, ) + diff --git a/octopi/library/tests_octopus/t_bin_threaded.cpp b/octopi/library/tests_octopus/t_bin_threaded.cpp new file mode 100644 index 00000000..df719f74 --- /dev/null +++ b/octopi/library/tests_octopus/t_bin_threaded.cpp @@ -0,0 +1,337 @@ +/*****************************************************************************\ +* * +* Name : test_entity_data_bin_threaded * +* Author : Chris Koeritz * +* * +******************************************************************************* +* Copyright (c) 2010-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __WIN32__ + #include +#endif + +using namespace application; +using namespace loggers; +using namespace octopi; +using namespace processes; +using namespace timely; + +// global constants... + +// how much data is the entity data bin allowed to hold at one time. +const int MAXIMUM_DATA_PER_ENTITY = 1 * KILOBYTE; +//tiny limit to test having too much data. + +// controls the timing of the thread that adds items. +const int MIN_ADDER_THREAD_PAUSE = 3; +const int MAX_ADDER_THREAD_PAUSE = 20; + +// controls the timing of the item deleting thread. +const int MIN_WHACKER_THREAD_PAUSE = 8; +const int MAX_WHACKER_THREAD_PAUSE = 70; + +// bound the randomly chosen pause time for the cleanup thread. +const int MIN_TIDIER_THREAD_PAUSE = 60; +const int MAX_TIDIER_THREAD_PAUSE = 500; + +// monk is kept asleep most of the time or he'd be trashing +// all our data too frequently. +const int MIN_MONK_THREAD_PAUSE = 2 * MINUTE_ms; +const int MAX_MONK_THREAD_PAUSE = 4 * MINUTE_ms; + +// the range of new items added whenever the creator thread is hit. +const int MINIMUM_ITEMS_ADDED = 1; +const int MAXIMUM_ITEMS_ADDED = 20; + +const int DEFAULT_THREADS = 90; + // the number of threads we create by default. + +const int DEFAULT_RUN_TIME = 80 * MINUTE_ms; +//2 * MINUTE_ms; + // the length of time to run the program. + +const int DATA_DECAY_TIME = 1 * MINUTE_ms; + // how long we retain unclaimed data. + +const int MONKS_CLEANING_TIME = 10 * SECOND_ms; + // a very short duration for data to live. + +#define LOG(to_print) printf("%s\n", (char *)astring(to_print).s()); +//CLASS_EMERGENCY_LOG(program_wide_logger().get(), to_print) + // our macro for logging with a timestamp. + +// global objects... + +chaos _rando; // our randomizer. + +// replace app_shell version with local randomizer, so all the static +// functions can employ it also. +#define randomizer() _rando + +entity_data_bin binger(MAXIMUM_DATA_PER_ENTITY); + +octopus_request_id create_request_id() +{ + // test the basic filling of the values in an entity. + octopus_request_id req_id; + if (randomizer().inclusive(1, 100) < 25) { + // some of the time we make a totally random entity id. + int sequencer = randomizer().inclusive(1, MAXINT - 10); + int add_in = randomizer().inclusive(0, MAXINT - 10); + int process_id = randomizer().inclusive(0, MAXINT - 10); + req_id._entity = octopus_entity(string_manipulation::make_random_name(), + process_id, sequencer, add_in); + } else { + // sometimes we use a less random identity. + int sequencer = randomizer().inclusive(1, 3); + int add_in = 12; + int process_id = randomizer().inclusive(1, 4); + req_id._entity = octopus_entity("boringentity", + process_id, sequencer, add_in); + } + req_id._request_num = randomizer().inclusive(1, MAXINT - 10); + return req_id; +} + +// this thread creates new items for the entity data bin. +class ballot_box_stuffer : public ethread +{ +public: + ballot_box_stuffer() : ethread(0) { + FUNCDEF("constructor"); + LOG("+creator"); + } + + virtual ~ballot_box_stuffer() { + FUNCDEF("destructor"); + LOG("~creator"); + } + + DEFINE_CLASS_NAME("ballot_box_stuffer"); + + void perform_activity(void *formal(data)) { + FUNCDEF("perform_activity"); + while (!should_stop()) { + // add a new item to the cache. + int how_many = randomizer().inclusive(MINIMUM_ITEMS_ADDED, + MAXIMUM_ITEMS_ADDED); + for (int i = 0; i < how_many; i++) { + string_array random_strings; + int string_count = randomizer().inclusive(1, 10); + // we create a random classifier, just to use up some space. + for (int q = 0; q < string_count; q++) { + random_strings += string_manipulation::make_random_name(); + } + unhandled_request *newbert = new unhandled_request(create_request_id(), + random_strings); + binger.add_item(newbert, create_request_id()); + } + // snooze. + int sleepy_time = randomizer().inclusive(MIN_ADDER_THREAD_PAUSE, + MAX_ADDER_THREAD_PAUSE); + time_control::sleep_ms(sleepy_time); + } + } + +}; + +// this thread eliminates entries in the ballot box. +class vote_destroyer : public ethread +{ +public: + vote_destroyer() : ethread(0) { + FUNCDEF("constructor"); + LOG("+destroyer"); + } + + virtual ~vote_destroyer() { + FUNCDEF("destructor"); + LOG("~destroyer"); + } + + DEFINE_CLASS_NAME("vote_destroyer"); + + void perform_activity(void *formal(data)) { + FUNCDEF("perform_activity"); + while (!should_stop()) { + // snag any old item and drop it on the floor. + octopus_request_id id; + infoton *found = binger.acquire_for_any(id); + WHACK(found); + // snooze. + int sleepy_time = randomizer().inclusive(MIN_WHACKER_THREAD_PAUSE, + MAX_WHACKER_THREAD_PAUSE); + time_control::sleep_ms(sleepy_time); + } + } +}; + +// this class makes sure the deadwood is cleaned out of the entity bin. +class obsessive_compulsive : public ethread +{ +public: + obsessive_compulsive() : ethread(0) { + FUNCDEF("constructor"); + LOG("+cleaner"); + } + + virtual ~obsessive_compulsive() { + FUNCDEF("destructor"); + LOG("~cleaner"); + } + + DEFINE_CLASS_NAME("obsessive_compulsive"); + + void perform_activity(void *formal(data)) { + FUNCDEF("perform_activity"); + while (!should_stop()) { + // make sure there's nothing rotting too long. + binger.clean_out_deadwood(DATA_DECAY_TIME); + // snooze. + int sleepy_time = randomizer().inclusive(MIN_TIDIER_THREAD_PAUSE, + MAX_TIDIER_THREAD_PAUSE); + time_control::sleep_ms(sleepy_time); + } + } +}; + +// this thread will destroy all data in the bins while cleaning furiously. +class monk_the_detective : public ethread +{ +public: + monk_the_detective() : ethread(0) { + FUNCDEF("constructor"); + LOG("+monk"); + } + + virtual ~monk_the_detective() { + FUNCDEF("destructor"); + LOG("~monk"); + } + + DEFINE_CLASS_NAME("monk_the_detective"); + + void perform_activity(void *formal(data)) { + FUNCDEF("perform_activity"); + while (!should_stop()) { + // one activation of monk has devastating consequences. we empty out + // the data one item at a time until we see no data at all. after + // cleaning each item, we ensure that the deadwood is cleaned out. + binger._ent_lock->lock(); +LOG(a_sprintf("monk sees %d items.", binger.items_held())); + while (binger.items_held()) { + // grab one instance of any item in the bin. + octopus_request_id id; + infoton *found = binger.acquire_for_any(id); + WHACK(found); + // also clean out things a lot faster than normal. + binger.clean_out_deadwood(MONKS_CLEANING_TIME); + } + binger._ent_lock->unlock(); +LOG(a_sprintf("after a little cleaning, monk sees %d items.", binger.items_held())); + // snooze. + int sleepy_time = randomizer().inclusive(MIN_MONK_THREAD_PAUSE, + MAX_MONK_THREAD_PAUSE); + time_control::sleep_ms(sleepy_time); + } + } +}; + +////////////// + +class test_entity_data_bin_threaded : public application_shell +{ +public: + test_entity_data_bin_threaded() : application_shell(class_name()) {} + + DEFINE_CLASS_NAME("test_entity_data_bin_threaded"); + + int execute(); +}; + +int test_entity_data_bin_threaded::execute() +{ + FUNCDEF("execute"); + + amorph thread_list; + + for (int i = 0; i < DEFAULT_THREADS; i++) { + ethread *t = NIL; + if (i == DEFAULT_THREADS - 1) { + // last item gets special treatment; we reserve this space for monk. + t = new monk_the_detective; + } else if (i % 3 == 0) { + t = new ballot_box_stuffer; + } else if (i % 3 == 1) { + t = new vote_destroyer; + } else { // i % 3 must = 2. + t = new obsessive_compulsive; + } + thread_list.append(t); + ethread *q = thread_list[thread_list.elements() - 1]; + if (q != t) + deadly_error(class_name(), func, "amorph has incorrect pointer!"); + // start the thread we added. + thread_list[thread_list.elements() - 1]->start(NIL); + } + + time_stamp when_to_leave(DEFAULT_RUN_TIME); + while (when_to_leave > time_stamp()) { + time_control::sleep_ms(100); + } + +// LOG("now cancelling all threads...."); + +// for (int j = 0; j < thread_list.elements(); j++) thread_list[j]->cancel(); + +// LOG("now stopping all threads...."); + +// for (int k = 0; k < thread_list.elements(); k++) thread_list[k]->stop(); + +// LOG("resetting thread list...."); + + thread_list.reset(); // should whack all threads. + + LOG("done exiting from all threads...."); + +//report the results: +// how many objects created. +// how many got destroyed. +// how many evaporated due to timeout. + + + guards::alert_message("t_bin_threaded:: works for all functions tested."); + return 0; +} + +HOOPLE_MAIN(test_entity_data_bin_threaded, ) + diff --git a/octopi/library/tests_octopus/t_entity.cpp b/octopi/library/tests_octopus/t_entity.cpp new file mode 100644 index 00000000..d9240982 --- /dev/null +++ b/octopi/library/tests_octopus/t_entity.cpp @@ -0,0 +1,133 @@ +/*****************************************************************************\ +* * +* Name : octopus_entity tester * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Checks that the octopus_entity class is behaving as expected. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __WIN32__ + #include +#else + #include +#endif + +const int ITERATE_EACH_TEST = 1000; + // the number of times to repeat each test operation. + +class test_entity : public application_shell +{ +public: + test_entity() : application_shell(class_name()) {} + DEFINE_CLASS_NAME("test_entity"); + virtual int execute(); +}; + +int test_entity::execute() +{ + chaos rando; + SET_DEFAULT_COMBO_LOGGER; + tcpip_stack stack; + + octopus_entity blankie; + if (!blankie.blank()) + deadly_error(class_name(), "emptiness test", + "the blank entity was not seen as empty."); + octopus_entity fullish("gurp", 28, 39, 4); + if (fullish.blank()) + deadly_error(class_name(), "emptiness test", + "the non-blank entity was seen as empty."); + + for (int i = 0; i < ITERATE_EACH_TEST; i++) { + // test the basic filling of the values in an entity. + octopus_entity blank_ent; + int sequencer = rando.inclusive(1, MAXINT - 10); + int add_in = rando.inclusive(0, MAXINT - 10); + octopus_entity filled_ent(stack.hostname(), application_configuration::process_id(), sequencer, + add_in); + blank_ent = octopus_entity(stack.hostname(), application_configuration::process_id(), sequencer, + add_in); + if (blank_ent != filled_ent) + deadly_error(class_name(), "simple reset test", + "failed to resolve to same id"); + astring text1 = filled_ent.to_text(); + astring text2 = blank_ent.to_text(); + if (text1 != text2) + deadly_error(class_name(), "to_text test", "strings are different"); +///log(text1); + octopus_entity georgio = octopus_entity::from_text(text2); +///log(georgio.to_text()); + if (georgio != filled_ent) + deadly_error(class_name(), "from_text test", + "entity is different after from_text"); + + octopus_request_id fudnix(filled_ent, 8232390); + astring text3 = fudnix.to_text(); + octopus_request_id resur = octopus_request_id::from_text(text3); + if (resur != fudnix) + deadly_error(class_name(), "from_text test", + "request id is different after from_text"); + + blank_ent = octopus_entity(); // reset it again forcefully. + blank_ent = octopus_entity(filled_ent.hostname(), filled_ent.process_id(), + filled_ent.sequencer(), filled_ent.add_in()); + if (blank_ent != filled_ent) + deadly_error(class_name(), "reset from attribs test", + "failed to resolve to same id"); +// log(a_sprintf("%d: ", i + 1) + filled_ent.mangled_form()); + + byte_array chunk1; + filled_ent.pack(chunk1); + octopus_entity unpacked1; + unpacked1.unpack(chunk1); + if (unpacked1 != filled_ent) + deadly_error(class_name(), "pack/unpack test", + "failed to return same values"); + + // test of entity packing and size calculation. + octopus_entity ent(string_manipulation::make_random_name(1, 428), + randomizer().inclusive(0, MAXINT/2), + randomizer().inclusive(0, MAXINT/2), + randomizer().inclusive(0, MAXINT/2)); + octopus_request_id bobo(ent, randomizer().inclusive(0, MAXINT/2)); + int packed_estimate = bobo.packed_size(); + byte_array packed_bobo; + bobo.pack(packed_bobo); + if (packed_bobo.length() != packed_estimate) + deadly_error(class_name(), "entity packed_size test", + "calculated incorrect packed size"); + } + + + log("octopus_entity:: works for those functions tested."); + return 0; +} + +//hmmm: tests the octopus entity object, +// can do exact text check if want but that's not guaranteed to be useful +// in the future. + +HOOPLE_MAIN(test_entity, ) + diff --git a/octopi/library/tests_octopus/t_file_transfer.cpp b/octopi/library/tests_octopus/t_file_transfer.cpp new file mode 100644 index 00000000..9deb90a7 --- /dev/null +++ b/octopi/library/tests_octopus/t_file_transfer.cpp @@ -0,0 +1,187 @@ +/*****************************************************************************\ +* * +* Name : test_file_transfer_tentacle * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Tests the file_transfer_tentacle without any networking involved. * +* * +******************************************************************************* +* Copyright (c) 2005-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s) + +class test_file_transfer_tentacle : public application_shell +{ +public: + test_file_transfer_tentacle() : application_shell(static_class_name()) {} + DEFINE_CLASS_NAME("test_dirtree_fcopy"); + int execute(); +}; + +int test_file_transfer_tentacle::execute() +{ + FUNCDEF("execute"); + + if (__argc < 3) { + log("\ +This program needs two parameters:\n\ +a directory for the source root and one for the target root.\n\ +Optionally, a third parameter may specify a starting point within the\n\ +source root.\n\ +Further, if fourth or more parameters are found, they are taken to be\n\ +files to include; only they will be transferred.\n"); + return 23; + } + + astring source_dir = __argv[1]; + astring target_dir = __argv[2]; + + astring source_start = ""; + if (__argc >= 4) { + source_start = __argv[3]; + } + + string_array includes; + if (__argc >= 5) { + for (int i = 4; i < __argc; i++) { + includes += __argv[i]; + } + } + + + outcome returned = recursive_file_copy::copy_hierarchy + (file_transfer_tentacle::COMPARE_SIZE_AND_TIME, source_dir, + target_dir, includes, source_start); + +/* + astring source_root = "snootums"; + if (source_start.t()) { + source_root += filename::default_separator() + source_start; + } + + tcpip_stack stack; + octopus ring_leader(stack.hostname(), 10 * MEGABYTE); + file_transfer_tentacle *tran = new file_transfer_tentacle(MAX_CHUNK, false); + ring_leader.add_tentacle(tran); + + outcome add_ret = tran->add_correspondence("snootums", source_dir, + 10 * MINUTE_ms); + if (add_ret != tentacle::OKAY) + deadly_error(class_name(), func, "failed to add the correspondence"); + + file_transfer_infoton *initiate = new file_transfer_infoton; + initiate->_request = true; + initiate->_command = file_transfer_infoton::TREE_COMPARISON; + initiate->_src_root = source_root; + initiate->_dest_root = target_dir; + directory_tree target_area(target_dir); + target_area.calculate(); + initiate->package_tree_info(target_area, includes); + + octopus_entity ent = ring_leader.issue_identity(); + octopus_request_id req_id(ent, 1); + outcome start_ret = ring_leader.evaluate(initiate, req_id); + if (start_ret != tentacle::OKAY) + deadly_error(class_name(), func, "failed to start the comparison"); + + file_transfer_infoton *reply_from_init + = (file_transfer_infoton *)ring_leader.acquire_specific_result(req_id); + if (!reply_from_init) + deadly_error(class_name(), func, "no response to tree compare start"); + + filename_list diffs; + byte_array pack_copy = reply_from_init->_packed_data; + if (!diffs.unpack(pack_copy)) + deadly_error(class_name(), func, "could not unpack filename list!"); +// LOG(astring("got list of diffs:\n") + diffs.text_form()); + + octopus client_spider(stack.hostname(), 10 * MEGABYTE); + file_transfer_tentacle *tran2 = new file_transfer_tentacle(MAX_CHUNK, false); + tran2->register_file_transfer(ent, source_root, target_dir, includes); + client_spider.add_tentacle(tran2); + + octopus_request_id resp_id(ent, 2); + outcome ini_resp_ret = client_spider.evaluate(reply_from_init, resp_id); + if (ini_resp_ret != tentacle::OKAY) + deadly_error(class_name(), func, "failed to process the start response!"); + + infoton *junk = client_spider.acquire_specific_result(resp_id); + if (junk) + deadly_error(class_name(), func, "got a response we shouldn't have!"); + + int iter = 0; + while (true) { +LOG(a_sprintf("ongoing chunk %d", ++iter)); + + // keep going until we find a broken reply. + file_transfer_infoton *ongoing = new file_transfer_infoton; + ongoing->_request = true; + ongoing->_command = file_transfer_infoton::PLACE_FILE_CHUNKS; + ongoing->_src_root = source_root; + ongoing->_dest_root = target_dir; + + octopus_request_id chunk_id(ent, iter + 10); + outcome place_ret = ring_leader.evaluate(ongoing, chunk_id); + if (place_ret != tentacle::OKAY) + deadly_error(class_name(), func, "failed to run ongoing transfer"); + + file_transfer_infoton *reply = (file_transfer_infoton *)ring_leader + .acquire_specific_result(chunk_id); + if (!reply) + deadly_error(class_name(), func, "failed to get ongoing transfer reply"); + + if (!reply->_packed_data.length()) { + LOG("hit termination condition: no data packed in for file chunks."); + break; + } + + byte_array copy = reply->_packed_data; + while (copy.length()) { + file_transfer_header head; + if (!head.unpack(copy)) + deadly_error(class_name(), func, "failed to unpack header"); +LOG(astring("header: ") + head.text_form()); +LOG(a_sprintf("size in array: %d", copy.length())); + if (copy.length() < head._length) + deadly_error(class_name(), func, "not enough length in array"); + copy.zap(0, head._length - 1); +LOG(a_sprintf("size in array now: %d", copy.length())); + } + if (copy.length()) + deadly_error(class_name(), func, "still had data in array"); + + octopus_request_id resp_id(ent, iter + 11); + outcome resp_ret = client_spider.evaluate(reply, resp_id); + if (resp_ret != tentacle::OKAY) + deadly_error(class_name(), func, "failed to process the transfer reply!"); + + } +*/ + + if (returned == common::OKAY) + guards::alert_message("file_transfer_tentacle:: works for those " + "functions tested."); + else + guards::alert_message(astring("file_transfer_tentacle:: failed with " + "outcome=") + recursive_file_copy::outcome_name(returned)); + return 0; +} + +HOOPLE_MAIN(test_file_transfer_tentacle, ) + diff --git a/octopi/library/tests_octopus/t_identity.cpp b/octopi/library/tests_octopus/t_identity.cpp new file mode 100644 index 00000000..eb7dd35f --- /dev/null +++ b/octopi/library/tests_octopus/t_identity.cpp @@ -0,0 +1,86 @@ +/*****************************************************************************\ +* * +* Name : octopus identity test * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Checks out the client identification methods in octopus. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////// + +class test_octopus_identity : public application_shell +{ +public: + test_octopus_identity() : application_shell(class_name()) {} + DEFINE_CLASS_NAME("test_octopus_identity"); + virtual int execute(); +}; + +int test_octopus_identity::execute() +{ + octopus logos("local", 18 * MEGABYTE); + + identity_infoton *ide = new identity_infoton; + octopus_request_id junk_id = octopus_request_id::randomized_id(); + // bogus right now. + + byte_array packed; + ide->pack(packed); + if (ide->packed_size() != packed.length()) + deadly_error(class_name(), "packing test", + astring("the packed size was different than expected.")); + + outcome ret = logos.evaluate(ide, junk_id); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "evaluate test", + astring("the evaluation failed with an error ") + + tentacle::outcome_name(ret)); +log("point a"); + + octopus_request_id response_id; // based on bogus from before. + infoton *response = logos.acquire_result(junk_id._entity, response_id); + if (!response) + deadly_error(class_name(), "acquire test", + astring("the acquire_result failed to produce a result.")); + + identity_infoton *new_id = dynamic_cast(response); + if (!new_id) + deadly_error(class_name(), "casting", + astring("the returned infoton is not the right type.")); + + octopus_entity my_ide = new_id->_new_name; + +log(astring("new id is: ") + my_ide.text_form()); + + if (my_ide.blank()) + deadly_error(class_name(), "retrieving id", + astring("the new entity id is blank.")); + + + log("octopus:: identity works for those functions tested."); + + return 0; +} + +HOOPLE_MAIN(test_octopus_identity, ) + diff --git a/octopi/library/tests_octopus/t_security.cpp b/octopi/library/tests_octopus/t_security.cpp new file mode 100644 index 00000000..9531ab6d --- /dev/null +++ b/octopi/library/tests_octopus/t_security.cpp @@ -0,0 +1,184 @@ +/*****************************************************************************\ +* * +* Name : octopus security test * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Checks out the login support for octopus. This just exercises the base * +* support which doesn't perform any extra verification on the user. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////// + +astring base_list[] = { "cli", "simp" }; + +SAFE_STATIC_CONST(string_array, simp_classifier, (2, base_list)) + +class simple_infoton : public infoton +{ +public: + astring futzle; + + simple_infoton() : infoton(simp_classifier()) {} + + virtual void pack(byte_array &packed_form) const { + futzle.pack(packed_form); + } + virtual bool unpack(byte_array &packed_form) { + if (!futzle.unpack(packed_form)) return false; + return true; + } + virtual int packed_size() const { return futzle.length() + 1; } + virtual clonable *clone() const { return new simple_infoton(*this); } + +private: +}; + +////////////// + +// provides a simple service to allow us to test whether the security is +// working or not. + +class simple_tentacle : public tentacle +{ +public: + simple_tentacle() : tentacle(simp_classifier(), true) {} + + virtual outcome reconstitute(const string_array &classifier, + byte_array &packed_form, infoton * &reformed) { + reformed = NIL; + if (classifier != simp_classifier()) return NO_HANDLER; + reformed = new simple_infoton; + if (!reformed->unpack(packed_form)) { + WHACK(reformed); + return GARBAGE; + } + return OKAY; + } + + virtual outcome consume(infoton &to_chow, + const octopus_request_id &formal(item_id), byte_array &transformed) { + transformed.reset(); + if (to_chow.classifier() != simp_classifier()) return NO_HANDLER; + // consume without doing anything. + return OKAY; + } + + virtual void expunge(const octopus_entity &formal(to_zap)) {} +}; + +////////////// + +//hmmm: this test should do a sample login octopus and do a login, reside for +// a while, log out, do another one, let it time out, try to access +// something with dead id hoping to be rejected, etc. + +class test_octopus_security : public application_shell +{ +public: + test_octopus_security() : application_shell(class_name()) {} + DEFINE_CLASS_NAME("test_octopus_security"); + virtual int execute(); +}; + +int test_octopus_security::execute() +{ + octopus logos("local", 18 * MEGABYTE); + simple_tentacle *tenty = new simple_tentacle; + logos.add_tentacle(tenty); + tenty = NIL; // octopus has charge of this now. + + // turn on security in logos. + simple_entity_registry *guardian = new simple_entity_registry; + logos.add_tentacle(new login_tentacle(*guardian), true); + + // create an entity to work with. + octopus_entity jimbo("localhost", application_configuration::process_id(), 128, 982938); + octopus_request_id req1(jimbo, 1); + + // add the user jimbo. + guardian->add_entity(jimbo, byte_array()); + + // create a piece of data to try running on tentacle. + simple_infoton testose; + simple_infoton *testose_copy = new simple_infoton(testose); + + // test that the simple tentacle allows the op. + outcome ret = logos.evaluate(testose_copy, req1); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "first test", + astring("the operation failed with an error ") + + tentacle::outcome_name(ret)); + + // create another entity to work with. + octopus_entity burfo("localhost", application_configuration::process_id(), 372, 2989); + octopus_request_id req2(burfo, 1); + + // try with an unlicensed user burfo... + testose_copy = new simple_infoton(testose); + ret = logos.evaluate(testose_copy, req2); + if (ret == tentacle::OKAY) + deadly_error(class_name(), "second test", + astring("the operation didn't fail when it should have.")); + else if (ret != tentacle::DISALLOWED) + deadly_error(class_name(), "second test", + astring("the operation didn't provide the proper outcome, it gave: ") + + tentacle::outcome_name(ret)); + + // remove the user jimbo. + guardian->zap_entity(jimbo); + + // test that jimbo fails too now. + testose_copy = new simple_infoton(testose); + ret = logos.evaluate(testose_copy, req1); + if (ret == tentacle::OKAY) + deadly_error(class_name(), "third test", + astring("the operation didn't fail when it should have.")); + else if (ret != tentacle::DISALLOWED) + deadly_error(class_name(), "third test", + astring("the operation didn't provide the proper outcome, it gave: ") + + tentacle::outcome_name(ret)); + + // add the user burfo in now instead. + guardian->add_entity(burfo, byte_array()); + + // test that burfo works. + testose_copy = new simple_infoton(testose); + ret = logos.evaluate(testose_copy, req2); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "fourth test", + astring("the operation failed with an error ") + + tentacle::outcome_name(ret)); + + log("octopus:: security works for those functions tested."); + + WHACK(guardian); + + return 0; +} + +HOOPLE_MAIN(test_octopus_security, ) + diff --git a/octopi/library/tests_octopus/t_unpacker.cpp b/octopi/library/tests_octopus/t_unpacker.cpp new file mode 100644 index 00000000..a12412a3 --- /dev/null +++ b/octopi/library/tests_octopus/t_unpacker.cpp @@ -0,0 +1,396 @@ +/*****************************************************************************\ +* * +* Name : unpacking octopus test * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* A test of octopuses used for unpacking flat structures. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//hmmm: provide equality ops to be able to check that same stuff +// came back out that went in. + +class test_unpacker : public application_shell +{ +public: + test_unpacker() : application_shell(class_name()) {} + DEFINE_CLASS_NAME("test_unpacker"); + virtual int execute(); + void test_unpacking(); +}; + +////////////// + +// the infotons here have a three level classifier. the outer level is +// for the benefit of the handler_arm tentacle that just checks that the +// group name is correct before passing off the request to its internal +// octopus. then the second level specifies which class of infotons are +// being managed. the third level specifies the leaf type of the infoton-- +// the specific type of data being wrapped. + +const char *base_list[] = { "gruntiak" }; + +SAFE_STATIC_CONST(string_array, base_classifier, (1, base_list)) + +const char *math_list[] = { "math" }; + +SAFE_STATIC_CONST(string_array, math_classifier, (base_classifier() + + string_array(1, math_list))) + +const char *addr_list[] = { "address" }; + +SAFE_STATIC_CONST(string_array, addr_classifier, (base_classifier() + + string_array(1, addr_list))) + +class address_ton : public infoton, public network_address +{ +public: + address_ton() : infoton(addr_classifier() + "leaf") {} + + virtual void pack(byte_array &packed_form) const { + network_address::pack(packed_form); + } + + virtual bool unpack(byte_array &packed_form) { + return network_address::unpack(packed_form); + } + + virtual int packed_size() const { + return 5 * sizeof(int) + 128 /*address estimate*/; + } + + virtual clonable *clone() const { + return new address_ton(*this); + } +}; + +//some floating point nums. +class float_ton : public infoton +{ +public: + float f1; + double d1; + + float_ton() : infoton(math_classifier() + "float") {} + + virtual void pack(byte_array &packed_form) const { + structures::attach(packed_form, f1); + structures::attach(packed_form, d1); + } + + virtual int packed_size() const { + return sizeof(double) + sizeof(float); + } + + virtual bool unpack(byte_array &packed_form) { + double hold; + if (!structures::detach(packed_form, hold)) return false; + f1 = float(hold); + if (!structures::detach(packed_form, d1)) return false; + return true; + } + + virtual clonable *clone() const { + return new float_ton(*this); + } +}; + +//an integer set. +class int_set_ton : public infoton +{ +public: + int_set nums; + + int_set_ton() : infoton(math_classifier() + "intset") {} + + virtual void pack(byte_array &packed_form) const { + structures::attach(packed_form, nums.elements()); + for (int i = 0; i < nums.elements(); i++) + structures::attach(packed_form, nums[i]); + } + + virtual int packed_size() const { + return sizeof(int) + nums.elements() * sizeof(int); + } + + virtual bool unpack(byte_array &packed_form) { + int len = 0; + nums.reset(); + if (!structures::detach(packed_form, len)) return false; + for (int i = 0; i < len; i++) { + int got = 0; + if (!structures::detach(packed_form, got)) return false; + nums += got; + } + return true; + } + + virtual clonable *clone() const { + return new int_set_ton(*this); + } +}; + +////////////// + +// handles network addresses. +class address_chomper : public tentacle_helper +{ +public: + address_chomper() + : tentacle_helper(addr_classifier().subarray(1, 1), true) {} +}; + +// handles floats and int_sets. +class numerical_chomper : public tentacle +{ +public: + numerical_chomper() : tentacle(math_classifier().subarray(1, 1), true) {} + + outcome reconstitute(const string_array &classifier, byte_array &packed_form, + infoton * &reformed) + { + reformed = NIL; + if (classifier.length() < 2) return BAD_INPUT; + astring key = classifier[1]; + if (key == "float") { + float_ton *to_return = new float_ton; + if (!to_return->unpack(packed_form)) { + WHACK(to_return); + return NIL; + } + reformed = to_return; + return OKAY; + } else if (key == "intset") { + int_set_ton *to_return = new int_set_ton; + if (!to_return->unpack(packed_form)) { + WHACK(to_return); + return NIL; + } + reformed = to_return; + return OKAY; + } else + return NO_HANDLER; + } + + outcome consume(infoton &formal(to_chow), const octopus_request_id &formal(item_id), + byte_array &transformed) + { transformed.reset(); return tentacle::BAD_INPUT; } + + virtual void expunge(const octopus_entity &formal(zapola)) {} +}; + +////////////// + +// delegates the unpacking to an internal tentacle. it peels off a level +// of classifier to find the real handler. +class outer_arm : public tentacle +{ +public: + outer_arm() + : tentacle(base_classifier(), true), + _unpackers("local", 10 * MEGABYTE), + _numer(new numerical_chomper), + _addron(new address_chomper) + { + // register the two tentacles. + outcome ret = _unpackers.add_tentacle(_numer); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding numerical tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + ret = _unpackers.add_tentacle(_addron); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding address tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + } + + ~outer_arm() { + // just reset the two tentacles, since the _unpackers octopus should + // clean them up. + _numer = NIL; + _addron = NIL; + } + + outcome reconstitute(const string_array &classifier, byte_array &packed_form, + infoton * &reformed) + { + // strip first word of classifier. + string_array real_class = classifier; + real_class.zap(0, 0); + // route to octopus. + return _unpackers.restore(real_class, packed_form, reformed); + } + + outcome consume(infoton &to_chow, const octopus_request_id &item_id, + byte_array &transformed) + { + transformed.reset(); + // strip first word of classifier. + string_array real_class = to_chow.classifier(); + real_class.zap(0, 0); + to_chow.set_classifier(real_class); + // route to octopus. + return _unpackers.evaluate((infoton *)to_chow.clone(), item_id); + } + + void expunge(const octopus_entity &formal(whackola)) {} + +private: + octopus _unpackers; + numerical_chomper *_numer; + address_chomper *_addron; +}; + +////////////// + +void test_unpacker::test_unpacking() +{ + octopus unpacky("local", 10 * MEGABYTE); + outer_arm *outer = new outer_arm; + outcome ret = unpacky.add_tentacle(outer); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding outer tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + + // test infoton fast packing. + int_set_ton jubjub; + jubjub.nums.add(299); + jubjub.nums.add(39274); + jubjub.nums.add(25182); + byte_array packed(10388); // have data in there to start. + infoton::fast_pack(packed, jubjub); + if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier()) + != packed.length() - 10388) + deadly_error(class_name(), "packing test", + astring("erroneous size calculated for first fast_pack")); + string_array shirley_class; + byte_array shirley_data; + packed.zap(0, 10387); // remove the original data. + + // testing the overhead calculation. + byte_array junk_jub; + jubjub.pack(junk_jub); + if (packed.length() != junk_jub.length() + + infoton::fast_pack_overhead(jubjub.classifier())) + deadly_error(class_name(), "test fast pack overhead", + "sizes differed from calculated"); + + if (!infoton::fast_unpack(packed, shirley_class, shirley_data)) + deadly_error(class_name(), "test infoton fast pack", + "failed shirley unpack"); + if (packed.length() != 0) + deadly_error(class_name(), "test infoton fast pack", + "shirley didn't consume all"); + if (shirley_class != jubjub.classifier()) + deadly_error(class_name(), "test infoton fast pack", + "inequal orig classifier"); + int_set_ton scroop; + if (!scroop.unpack(shirley_data)) + deadly_error(class_name(), "test infoton fast pack", + "failed scroop unpack"); + if (shirley_data.length()) + deadly_error(class_name(), "test infoton fast pack", + "scroop didn't consume all"); + if (scroop.nums.length() != 3) + deadly_error(class_name(), "test infoton fast pack", + "wrong length in scroop"); + if ( (scroop.nums[0] != jubjub.nums[0]) || (scroop.nums[1] != jubjub.nums[1]) + || (scroop.nums[2] != jubjub.nums[2]) ) + deadly_error(class_name(), "test infoton fast pack", + "erroneous information"); + + byte_array fasting; + infoton::fast_pack(fasting, jubjub); + if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier()) + != fasting.length()) + deadly_error(class_name(), "packing test", + astring("erroneous size calculated for second fast_pack")); + + // another test of the overhead calculator. + byte_array junk_fast; + jubjub.pack(junk_fast); + if (fasting.length() != junk_fast.length() + + infoton::fast_pack_overhead(jubjub.classifier())) + deadly_error(class_name(), "test fast pack overhead 2", + "sizes differed from calculated"); + + string_array nudge_class; + byte_array nudge_data; + if (!infoton::fast_unpack(fasting, nudge_class, nudge_data)) + deadly_error(class_name(), "test infoton fast pack", "fast pack failed to unpack"); + if (fasting.length()) + deadly_error(class_name(), "test infoton fast pack", "fast pack didn't consume all"); + int_set_ton croup; + if (!croup.unpack(nudge_data)) + deadly_error(class_name(), "test infoton fast pack", "croup wouldn't unpack"); + if ( (croup.nums[0] != jubjub.nums[0]) || (croup.nums[1] != jubjub.nums[1]) + || (croup.nums[2] != jubjub.nums[2]) ) + deadly_error(class_name(), "test infoton fast pack", "croup has errors"); + byte_array chunkmo; + chunkmo += 0x23; + chunkmo += 0xf8; + chunkmo += 0x37; + chunkmo += 0x65; + address_ton norf; + (network_address &)norf = network_address(internet_address + (chunkmo, "urp", 23841)); + chunkmo.reset(); + infoton::fast_pack(chunkmo, norf); + string_array clarfiator; + byte_array pacula; + if (!infoton::fast_unpack(chunkmo, clarfiator, pacula)) + deadly_error(class_name(), "test fast_unpack", "chunkmo has errors"); + infoton *scrung = NIL; +//log(astring("classif is ") + clarfiator.text_form()); + + outcome scrung_ret = unpacky.restore(clarfiator, pacula, scrung); + if (scrung_ret != tentacle::OKAY) + deadly_error(class_name(), "test fast_unpack", + a_sprintf("can't restore scrung: %s", + tentacle::outcome_name(scrung_ret))); + address_ton *rescrung = dynamic_cast(scrung); + if (!rescrung) + deadly_error(class_name(), "test fast_unpack", "wrong dynamic type for scrung"); + address_ton &prescrung = *rescrung; + if ((network_address &)prescrung != (network_address &)norf) + deadly_error(class_name(), "test fast_unpack", "wrong network address restored"); + WHACK(scrung); +} + +const int MAXIMUM_TESTS = 10; + // was added to check for memory leaks. + +int test_unpacker::execute() +{ + int iters = 0; + while (iters++ < MAXIMUM_TESTS) { +//log(a_sprintf("iter #%d", iters)); + test_unpacking(); + } + log("unpacking octopus:: works for all functions tested."); +//time_control::sleep_ms(30000); + return 0; +} + +HOOPLE_MAIN(test_unpacker, ) +