From: Fred T. Hamster Date: Sat, 14 Feb 2026 01:17:53 +0000 (-0500) Subject: breaking changes - tests for octopus and cromp X-Git-Url: https://feistymeow.org/gitweb/?a=commitdiff_plain;h=1d01ecfd3f031d80f04d70686dc768f2f7453ca2;p=feisty_meow.git breaking changes - tests for octopus and cromp these test sets have been out in the cold for a while, and now we're bringing them back in for a defrost. they will not build for a bit at least. --- diff --git a/octopi/library/makefile b/octopi/library/makefile index 29af249d..7f4a2053 100644 --- a/octopi/library/makefile +++ b/octopi/library/makefile @@ -6,9 +6,9 @@ BUILD_BEFORE = octopus \ tentacles \ cromp \ synchronic \ - tests_sockets - -# tests_octopus + tests_cromp \ + tests_octopus \ + tests_sockets include rules.def diff --git a/octopi/library/tests_cromp/cromp_decoder.cpp b/octopi/library/tests_cromp/cromp_decoder.cpp new file mode 100644 index 00000000..6e9ff9e6 --- /dev/null +++ b/octopi/library/tests_cromp/cromp_decoder.cpp @@ -0,0 +1,112 @@ +/*****************************************************************************\ +* * +* Name : cromp_decoder app * +* Author : Chris Koeritz * +* * +******************************************************************************* +* 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 +#include +#include + +#include + +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s) +#define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger(), s) + +const int MAX_LINE = 2048; + // the longest line we'll bother to try to process. + +class cromp_decoder : public application_shell +{ +public: + cromp_decoder(); + ~cromp_decoder(); + + virtual int execute(); + + IMPLEMENT_CLASS_NAME("cromp_decoder"); +}; + +//////////////////////////////////////////////////////////////////////////// + +cromp_decoder::cromp_decoder() : application_shell(class_name()) {} + +cromp_decoder::~cromp_decoder() {} + +int cromp_decoder::execute() +{ + FUNCDEF("execute"); + + BASE_LOG("\ +This application will decode a cromp entity and report the different values"); + BASE_LOG("\ +that are encoded into it."); + + istring buffer; // we'll read input from the user into this. + + while (true) { + BASE_LOG("Please enter the entity (or hit just enter to exit).") + + buffer = istring('\0', MAX_LINE + 10); // reset the buffer. + char *buf2 = fgets(buffer.s(), MAX_LINE, stdin); + if (buf2 != buffer.s()) { + deadly_error(class_name(), func, + "memory was allocated when we didn't want it to be."); + } + + buffer.shrink(); + buffer.strip("\r\n", istring::FROM_END); + if (!buffer.length()) break; + + // make sure they didn't actually give us a request id. + int indy = buffer.find('/'); + if (non_negative(indy)) buffer.zap(indy, buffer.end()); + + octopus_entity ent = octopus_entity::from_text(buffer); + if (ent.blank()) { + BASE_LOG("That entity was blank or invalid."); + BASE_LOG(""); + continue; + } + + BASE_LOG(""); + BASE_LOG(""); + BASE_LOG("Entity contains:"); + BASE_LOG(""); + BASE_LOG(isprintf("\tProcess ID=%d", ent.process_id())); + BASE_LOG(isprintf("\tSequencer=%d", ent.sequencer())); + BASE_LOG(isprintf("\tChaotic Addin=%d", ent.add_in())); + + istring host; + machine_uid machine; + bool worked = cromp_common::decode_host(ent.hostname(), host, machine); + if (!worked) { + BASE_LOG("Failed to decode the hostname! Was it a valid entity?"); + continue; + } + BASE_LOG(istring("\tPartial Hostname=") + host); + BASE_LOG(istring("\tMachine UID=") + machine.text_form()); + BASE_LOG(""); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// + +HOOPLE_MAIN(cromp_decoder, ) + diff --git a/octopi/library/tests_cromp/crompish_pax.h b/octopi/library/tests_cromp/crompish_pax.h new file mode 100644 index 00000000..23974b60 --- /dev/null +++ b/octopi/library/tests_cromp/crompish_pax.h @@ -0,0 +1,99 @@ +#ifndef CROMPISH_PAX_GROUP +#define CROMPISH_PAX_GROUP + +/*****************************************************************************\ +* * +* Name : crompish packets for tester * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Some simple transactions that can be used for the CROMP tester. * +* * +******************************************************************************* +* 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 + +using namespace geometric; + +class bubble : public infoton +{ +public: + bubble(int data_segment_size = 0, const screen_rectangle &boundaries + = screen_rectangle(), int color = 0) + // constructs a bubble within the "boundaries" that has "color" and a data + // segment size specified by "data_segment_size". the color definitions + // reside elsewhere. + : infoton(bubble_classing()), _data() + { reset(data_segment_size, boundaries, color); } + + const string_array &bubble_classing() { + static istring bubbs[2] = { "bubble", "rubble" }; + static string_array barray(2, bubbs); + return barray; + } + + void reset(int data_segment_size, const screen_rectangle &boundaries, + int color) { + _color = color; + _bounds = boundaries; + _data.reset(data_segment_size); + } + + int data_length() const { return _data.length(); } + + clonable *clone() const { return cloner(*this); } + + byte_array &data() { return _data; } + + int non_data_overhead() const { return packed_size() - _data.length(); } + + virtual void pack(byte_array &packed_form) const { + basis::attach(packed_form, _color); + _bounds.pack(packed_form); + basis::attach(packed_form, _data); + } + + int packed_size() const { + return _data.length() + 2 * sizeof(int) // packed byte array. + + sizeof(int) // packed color. + + 4 * sizeof(int); // packed screen rectangle. + } + + virtual bool unpack(byte_array &packed_form) { + if (!basis::detach(packed_form, _color)) return false; + if (!_bounds.unpack(packed_form)) return false; + if (!basis::detach(packed_form, _data)) return false; + return true; + } + +private: + screen_rectangle _bounds; + int _color; + byte_array _data; +}; + +//////////////////////////////////////////////////////////////////////////// + +class bubbles_tentacle : public tentacle_helper +{ +public: + bubbles_tentacle(bool backgrounded) + : tentacle_helper(bubble().classifier(), backgrounded) + {} +}; + +#endif + diff --git a/octopi/library/tests_cromp/makefile b/octopi/library/tests_cromp/makefile new file mode 100644 index 00000000..391d36f4 --- /dev/null +++ b/octopi/library/tests_cromp/makefile @@ -0,0 +1,19 @@ +CONSOLE_MODE = t + +include cpp/variables.def + +PROJECT = test_cromp +TYPE = test +TARGETS = test_cromp_client.exe test_cromp_server.exe test_many_cromp.exe +#DEFINITIONS += USE_HOOPLE_DLLS +LAST_TARGETS = create_decoder_ring +#LOCAL_LIBS_USED = basis i_library i_communication +USE_SSL = t +#VCPP_USE_SOCK = t +RUN_TARGETS = $(ACTUAL_TARGETS) + +include cpp/rules.def + +create_decoder_ring: + $(MAKE) -f makefile.decoder + diff --git a/octopi/library/tests_cromp/makefile.decoder b/octopi/library/tests_cromp/makefile.decoder new file mode 100644 index 00000000..a54e4ae8 --- /dev/null +++ b/octopi/library/tests_cromp/makefile.decoder @@ -0,0 +1,17 @@ +CONSOLE_MODE = t + +include cpp/variables.def + +PROJECT = decoder_ring +TYPE = application +TARGETS = cromp_decoder.exe +LOCAL_LIBS_USED = basis +#ifeq "$(COMPILER)" "VISUAL_CPP" +# SOURCE += cromp_decoder_version.rc +#endif +#USE_SSL = t +#VCPP_USE_SOCK = t +#RUN_TARGETS = $(ACTUAL_TARGETS) + +include cpp/rules.def + diff --git a/octopi/library/tests_cromp/test_cromp_client.cpp b/octopi/library/tests_cromp/test_cromp_client.cpp new file mode 100644 index 00000000..b65d87fb --- /dev/null +++ b/octopi/library/tests_cromp/test_cromp_client.cpp @@ -0,0 +1,798 @@ +/*****************************************************************************\ +* * +* Name : test_cromp_client * +* Author : Chris Koeritz * +* * +******************************************************************************* +* 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 "crompish_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#undef LOG +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s) + +#define DEBUG_TESTER + // uncomment for noisier version. + +// the number of transactions to send during a test. if timing connection +// duration, then use a maximum of 1. if timing speed of operation once +// connected, use a large number. +//const int MAXIMUM_SENDS = 10008; +const int MAXIMUM_SENDS = 100008; +//const int MAXIMUM_SENDS = 10000008; + // have had success with up to 10000000 sends using small data segments. + +const int NUMBER_OF_THREADS = 1; +//const int NUMBER_OF_THREADS = 10; +//const int NUMBER_OF_THREADS = 20; + // the number of simultaneous actors on the single cromp_client. + +//const int GRABBER_THREADS = 5; +const int GRABBER_THREADS = 0; + // the number of threads that just pluck at the cromp_client trying to + // interfere with the testing threads. + +//const int MAX_SEND_TRIES = 0; // don't pause. +const int MAX_SEND_TRIES = 1; // try to get stuff out but don't wait long. +//const int MAX_SEND_TRIES = 5; // wait a reasonable amount of times to send. +//const int MAX_SEND_TRIES = 10000; // force it to get out, hopefully. + // the number of times we try to push the sends out. zero means never + // try to push anything, just add it to the buffer. 1 or more is that + // many tries to push the send. + +//const int CHECKPOINT_SIZE = 1000; +//const int CHECKPOINT_SIZE = 100; +const int CHECKPOINT_SIZE = 100; + // prints a counter out when we reach a multiple of this many sends. + +//const int DATA_SEGMENT_SIZE = 0; +const int DATA_SEGMENT_SIZE = 64; +//const int DATA_SEGMENT_SIZE = 128 * KILOBYTE; +//const int DATA_SEGMENT_SIZE = 1 * MEGABYTE; + // the chunk size that we attach. + +const int REPORTING_INTERVAL = 10 * SECOND_ms; + // this is the period between reports on how the test is going. + +//***this is where we are in testing the faux dual cpu problem. +//***the longer delay shows the problem more easily. the shorter delay +//***is being used for a long test. +const int MAXIMUM_ACQUISITION_DELAY = 8 * SECOND_ms; +//const int MAXIMUM_ACQUISITION_DELAY = int(0.5 * SECOND_ms); + // the longest we'll snooze off waiting for pending receptions to occur. + +//const int MAXIMUM_PENDING_REQUESTS = 1; +const int MAXIMUM_PENDING_REQUESTS = 108; + // this is a threshold for the number of requests; once hit, we start + // awaiting the responses. + +//const int PENDING_REQUESTS_FORCED = 3; +//const int PENDING_REQUESTS_FORCED = 80; +const int PENDING_REQUESTS_FORCED = MAXIMUM_PENDING_REQUESTS; + // when we've been forced to gather some pending responses to previous + // requests, this is how many we'll try to get at once. numbers closer + // to the MAXIMUM_PENDING_REQUESTS will force more synchrony. + +const int CHANCE_OF_RECONSTRUCT = 14; + // how frequently a bus reconstruction occurs, in 1000. + +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s) +#define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger(), s) + +class cromp_client_tester : public application_shell +{ +public: + cromp_client_tester(); + ~cromp_client_tester(); + + virtual int execute(); + + IMPLEMENT_CLASS_NAME("cromp_client_tester"); + + void bite_server(basis::set &ids, + basis::set &delinquents, void *originator); + // performs the big chunk of testing. the "ids" are the history of the + // sends that were made and they're managed by this method. the + // "originator" is a tag we can use to generate unique print outs. + + int print_instructions(); + //!< shows how to use the command line options for this tester. + + void grab_items(); + //!< tries to retrieve things from the socket. + + void cause_object_reconstruction(); + //!< makes the cromp client object be zapped and redone. + + void increment_thread_count() { + FUNCDEF("increment_thread_count"); + auto_synchronizer l(*_lock); + _threads_active++; +//LOG(isprintf("count now %d", _threads_active)); + } + + void decrement_thread_count() { + FUNCDEF("decrement_thread_count"); + auto_synchronizer l(*_lock); + _threads_active--; +//LOG(isprintf("count now %d", _threads_active)); + } + + void report(const time_stamp &start_time, double bytes_transmitted, + double conversations); + // describes how the test is going. + +private: + cromp_client *_uplink; // provides the connection and transmission services. + + mutex *_lock; // protects the objects below. + int _threads_active; // the number of transmitter threads running. + time_stamp _last_report; // when we last reported on progress. + double _finished_loops; // counts number of loops we've achieved. + bool _encryption; // true if we're encrypting. + int _send_count; //!< number of sends in this test. + int _thread_count; //!< number of threads in test. + int _grabber_count; //!< number of threads interfering with retrieve. + int _send_tries; //!< how many times to try send if not all data got out. + int _checkpoint_count; //!< items seen between printing of counter. + int _dataseg_size; //!< size of bytes added to test packets. + int _report_interval; //!< how frequently to show the report. + int _snooze_duration; //!< time wasted between each send. + bool _rpc_style; //!< true if emulating RPC and waiting for each item. + bool _reconstruct_object; //!< true if we periodically tear down object. + internet_address _server_loc; //!< holds onto the requested address. + + void look_for_receipts(int count, basis::set &ids, + basis::set &delinquents, bool wait = false); + // attempts to get "count" items from the list of "ids". +}; + +//////////////////////////////////////////////////////////////////////////// + +class bitey_thread : public ithread +{ +public: + bitey_thread(cromp_client_tester &parent) + : ithread(), _parent(parent) {} + + void perform_activity(void *formal(ptr)) { + FUNCDEF("perform_activity"); + _parent.increment_thread_count(); + _parent.bite_server(_ids, _delinquents, this); + _parent.decrement_thread_count(); + } + +private: + cromp_client_tester &_parent; + basis::set _ids; // the ids for commands we've sent. + basis::set _delinquents; // missing ids during rcv. +}; + +//////////////////////////////////////////////////////////////////////////// + +//hmmm: next stop; inject the types of items they're expecting in grab_items. + +class grabby_thread : public ithread +{ +public: + grabby_thread(cromp_client_tester &parent) + : ithread(), _parent(parent) {} + + void perform_activity(void *formal(ptr)) { + while (!should_stop()) { + _parent.grab_items(); + if (_rando.inclusive(0, 100) > 10) + portable::sleep_ms(_rando.inclusive(5, 38)); + } + } + +private: + cromp_client_tester &_parent; + chaos _rando; +}; + +//////////////////////////////////////////////////////////////////////////// + +cromp_client_tester::cromp_client_tester() +: application_shell("cromp_client_tester"), + _uplink(NIL), + _lock(new mutex), + _threads_active(0), + _finished_loops(0.0), + _encryption(false), + _send_count(0), + _thread_count(0), + _grabber_count(0), + _send_tries(0), + _checkpoint_count(0), + _dataseg_size(0), + _report_interval(0), + _snooze_duration(0), + _rpc_style(false), + _reconstruct_object(false), + _server_loc() +{ + FUNCDEF("constructor"); + LOG(""); + LOG(""); + + command_line args(__argc, __argv); +//LOG(isprintf("argc is %d and first is %s", __argc, __argv[0])); + + int indy = 0; + if (args.find("help", indy, false) + || (args.find("?", indy, false)) + || (args.find('?', indy, false)) ) { + print_instructions(); + exit(0); + } + + // check for a port on the command line. + istring port_text; + int port = 5678; + if (args.get_value("port", port_text, false)) { + LOG(istring("using port: ") + port_text); + port = port_text.convert(5678); + } + _server_loc.port = port; + +//hmmm:normalize host so this can take either name or IP. + + indy = 0; + if (args.find("encrypt", indy, false) || (args.find('e', indy, true)) ) { + // they're saying that we should encrypt the communication. + LOG("turning on encryption."); + _encryption = true; + } + + indy = 0; + if (args.find("rpc", indy, false) || (args.find('R', indy, true)) ) { + // this is telling us to turn on RPC mode. we will make each request and + // reply pair synchronous, i.e., each reply will be awaited for when a + // request has been made. + LOG("turning on RPC style requests."); + _rpc_style = true; + } + + // check for a hostname on the command line. + istring hostname("local"); + istring host_temp; + if (args.get_value("host", host_temp, false)) { + LOG(istring("using host: ") + host_temp); + hostname = host_temp; + } +LOG(istring("using host: ") + hostname); + strcpy(_server_loc.hostname, hostname.s()); + + istring send_temp; + int send_count = MAXIMUM_SENDS; + if (args.get_value("sends", send_temp, false)) { + LOG(istring("using send count: ") + send_temp); + send_count = send_temp.convert(send_count); + if (send_count <= 0) send_count = 1; + } + _send_count = send_count; + + istring thread_temp; + int thread_count = NUMBER_OF_THREADS; + if (args.get_value("threads", thread_temp, false)) { + LOG(istring("using thread count: ") + thread_temp); + thread_count = thread_temp.convert(thread_count); + if (thread_count <= 0) thread_count = 1; + } + _thread_count = thread_count; + + istring grabber_temp; + int grabber_count = GRABBER_THREADS; + if (args.get_value("grab", grabber_temp, false)) { + LOG(istring("using grabber count: ") + grabber_temp); + grabber_count = grabber_temp.convert(grabber_count); + if (grabber_count < 0) grabber_count = 0; + } + _grabber_count = grabber_count; + + istring send_tries_temp; + int send_tries = MAX_SEND_TRIES; + if (args.get_value("trysend", send_tries_temp, false)) { + LOG(istring("using send tries: ") + send_tries_temp); + send_tries = send_tries_temp.convert(send_tries); + if (send_tries < 0) send_tries = 0; + } + _send_tries = send_tries; + +//hmmm: how tiresome. how about a macro here? could help in general +// with command_line also. + + istring checkpoint_temp; + int checkpoint_count = CHECKPOINT_SIZE; + if (args.get_value("print", checkpoint_temp, false)) { + LOG(istring("using checkpoint count: ") + checkpoint_temp); + checkpoint_count = checkpoint_temp.convert(checkpoint_count); + if (checkpoint_count <= 0) checkpoint_count = 1; + } + _checkpoint_count = checkpoint_count; + + istring dataseg_temp; + int dataseg_size = DATA_SEGMENT_SIZE; + if (args.get_value("dataseg", dataseg_temp, false)) { + LOG(istring("using dataseg size: ") + dataseg_temp); + dataseg_size = dataseg_temp.convert(dataseg_size); + if (dataseg_size < 0) dataseg_size = 0; + } + _dataseg_size = dataseg_size; + + istring report_temp; + int report_interval = REPORTING_INTERVAL; + if (args.get_value("report", report_temp, false)) { + LOG(istring("using report interval: ") + report_temp); + report_interval = report_temp.convert(report_interval); + if (report_interval <= 0) report_interval = 1; + report_interval *= SECOND_ms; // convert to milliseconds. + } + _report_interval = report_interval; + + istring snooze_temp; + int snooze_duration = 0; // no snooze by default. + if (args.get_value("snooze", snooze_temp, false)) { + LOG(istring("using snooze duration: ") + snooze_temp); + snooze_duration = snooze_temp.convert(snooze_duration); + if (snooze_duration < 0) snooze_duration = 0; + } + _snooze_duration = snooze_duration; + + if (args.find("reconstruct", indy, false)) { + LOG("saw reconstruct flag; will periodically tear down object."); + _reconstruct_object = true; + } + +LOG(istring("opening at ") + _server_loc.text_form()); + _uplink = new cromp_client(_server_loc); + + _uplink->add_tentacle(new bubbles_tentacle(false)); +//we don't need backgrounding right now. +} + +cromp_client_tester::~cromp_client_tester() +{ + WHACK(_lock); + WHACK(_uplink); +} + +int cromp_client_tester::print_instructions() +{ + istring name = filename(__argv[0]).basename().raw(); + log(isprintf("%s usage:", name.s())); + log(""); + log(isprintf("\ +This program connects to a cromp test server and exchanges packets to test\n\ +the performance of the cromp protocol. All command line flags are optional\n\ +but can be added to specify how the test should be performed. Currently,\n\ +the valid options are:\n\ + --help\tShow this set of command-line help.\n\ + -?\t\tditto.\n\ + --port N\tConnect to the server on the port specified.\n\ + --host X\tConnect to server at IP address or hostname X.\n\ + --encrypt\tEncrypt the connection. Server must do this also.\n\ + -e\t\tditto.\n\ + --sends N\tThe number of sends to perform.\n\ + --threads N\tNumber of threads competing for single cromp link.\n\ + --grab N\tNumber of additional threads stressing retrievals.\n\ + --trysend N\tCount of tries for sending if not all data went out.\n\ + --print N\tItems handled in between showing send counter.\n\ + --dataseg N\tSize of extra data packed in each test packet.\n\ + --report N\tDuration of time between reports, in seconds.\n\ + --snooze N\tSleep N ms between each send; this invalidates timing info.\n\ + --rpc\tEmulate Remote Procedure Call by awaiting each response.\n\ + -R\t\tditto\n\ +")); + return -3; +} + +void cromp_client_tester::look_for_receipts(int count, + basis::set &ids, + basis::set &delinquents, bool wait) +{ + FUNCDEF("look_for_receipts"); + infoton *received = NIL; + while (count--) { + if (!ids.length()) break; // nothing to check on. + octopus_request_id the_id = ids[0]; + ids.zap(0, 0); // take out the one we're inspecting right now. + + time_stamp start_acquire; + int delay = MAXIMUM_ACQUISITION_DELAY; + if (wait) delay = 2 * MINUTE_ms; // force a long delay. + outcome ret = _uplink->acquire(received, the_id, delay); + int acquire_duration = int(time_stamp().value() - start_acquire.value()); + if (acquire_duration >= MAXIMUM_ACQUISITION_DELAY - 1) { + LOG("passed time limit for acquire! this is the faux dual-cpu bug!"); + LOG(isprintf("there were %d items left to acquire.", count)); + LOG(isprintf("pending %d bytes to send, %d bytes accumulated.", + _uplink->pending_sends(), _uplink->accumulated_bytes())); + LOG(isprintf("the data bin had %d items awaiting pickup.", + _uplink->octo()->responses().items_held())); + if (ret != cromp_client::TIMED_OUT) { + LOG("cromp client lied about outcome?? didn't call this timed out!!"); + } + } + + if (ret != cromp_client::OKAY) { + if (ret != cromp_client::TIMED_OUT) { + LOG(istring("failed to acquire the response--got error ") + + cromp_client::outcome_name(ret)); + // give it another chance later. + ids += the_id; +LOG(isprintf("moved %s back to main id queue.", the_id.text_form().s())); + } else { + if (delinquents.member(the_id)) + continuable_error(class_name(), func, + istring("a delinquent response is still missing: ") + + the_id.text_form()); + // if we hadn't already seen it, we'll watch for it next time. + delinquents += the_id; +LOG(isprintf("added %s to delinquents.", the_id.text_form().s())); + } + return; + } + +if (!received) { +deadly_error(class_name(), func, +"received packet was NIL even though outcome was OKAY!"); +} + + // check that the right type is coming back to us. + bubble *cast = dynamic_cast(received); + if (!cast) { + continuable_error(class_name(), func, istring("got the wrong type " + "of response: ") + received->classifier().text_form()); + } + + // if we had a problem with this item earlier, we remove it since it + // succeeded this time. + if (delinquents.member(the_id)) + delinquents.remove(the_id); + WHACK(received); + } +} + +void cromp_client_tester::bite_server(basis::set &ids, + basis::set &delinquents, + void *originator) +{ + FUNCDEF("bite_server"); + octopus_request_id cmd_id; + +/// LOG(timestamp(true, true) + " starting..."); + + outcome ret; + + double overall_sent = 0; + + // this computes the size of the exchange object with no extra data attached. + byte_array temp; + bubble test_size(_dataseg_size, screen_rectangle(0, 120, 220, 280), + 238843); + test_size.data().reset(); + // set the data segment to zero length. + test_size.pack(temp); + int base_length = temp.length(); + // this is the base packed length of the bubble object. + + int failure_count = 0; + + time_stamp start; // record when our testing started. + + for (int sends = 1; sends <= _send_count; sends++) { + bubble to_send(_dataseg_size, screen_rectangle(0, 120, 220, 280), + 238843); + int curr_sending = to_send.data_length() + base_length * 2; + overall_sent += curr_sending; + // we compute the overall sent by what's sent in the request (which is + // of the base length plus the attached array size) and the reply (which + // is the base length only since the server resets the data attachment). + // we go ahead and count it as sent before the send, since we're going + // to bomb out if the send doesn't work. + ret = _uplink->submit(to_send, cmd_id, _send_tries); + switch (ret.value()) { + case cromp_client::OKAY: { + // complete success in sending that chunk out. + ids.add(cmd_id); // record it. + if (_rpc_style) { + // this call is used to force single requests and replies RPC style. + look_for_receipts(1, ids, delinquents, true); + } + // sleep if we were asked to. + if (_snooze_duration) { + _uplink->keep_alive_pause(_snooze_duration, 60); + look_for_receipts(1, ids, delinquents); + } + break; + } + case cromp_client::TOO_FULL: { +//treating as failure right now. +BASE_LOG("got too full outcome!"); + sends--; + overall_sent -= curr_sending; + continue; + break; + } + case cromp_client::TIMED_OUT: { +//treating as failure right now. +BASE_LOG("got timed out outcome!"); + sends--; + overall_sent -= curr_sending; + continue; + break; + } + default: { + // a failure case that we have no other handling for. + if (failure_count++ < 20) { + sends--; // skip back for the failed one. + overall_sent -= curr_sending; // remove unsent portion. + LOG(istring("got failure outcome ") + cromp_client::outcome_name(ret) + + " from attempt to submit request."); + if (_snooze_duration) { + _uplink->keep_alive_pause(_snooze_duration, 60); + } + continue; // try again. + } + continuable_error(class_name(), func, + istring("failed to submit the request--got error ") + + cromp_client::outcome_name(ret)); + break; + } + } + + _finished_loops += 1.0; + + if (ids.elements() > MAXIMUM_PENDING_REQUESTS) { + // grab some of the items waiting. hopefully they're back by now. + look_for_receipts(PENDING_REQUESTS_FORCED, ids, delinquents); + } + + if (! (sends % _checkpoint_count)) { + BASE_LOG(isprintf("%x send #%d", originator, sends)); + } + } + BASE_LOG(isprintf("%x final send #%d", originator, _send_count)); + +/// LOG(timestamp(true, true) + " done."); +/// LOG(isprintf("sent %d items.", _send_count)); + + look_for_receipts(ids.elements(), ids, delinquents); + + LOG(isprintf("concluded %d test requests and responses.", _send_count)); +} + +void cromp_client_tester::grab_items() +{ + FUNCDEF("grab_items"); + octopus_request_id id(_uplink->entity(), -12); + // look for an id we don't expect to have any thing waiting for. + infoton *found = NIL; + outcome ret = _uplink->retrieve_and_restore(found, id, 0); + WHACK(found); +} + +void cromp_client_tester::report(const time_stamp &start_time, + double bytes_transmitted, double conversations) +{ + FUNCDEF("report"); + throughput_counter bandwidth; // calculator for communication speed. + double duration = time_stamp().value() - start_time.value(); + // the elapsed duration so far. + bandwidth.add_run(bytes_transmitted, duration, conversations * 2); + // create a portrait of how the run has progressed. we multiply the + // conversations by two since we are counting both the request and the + // response (send and receive) as a transfer. + + // calculate the number of bytes per item for real as it plays out in + // cromp sending. + double bytes_per_item = bandwidth.bytes_sent() / bandwidth.number_of_sends(); + + bubble my_bubble(_dataseg_size); // an exemplar for our sends. + + // calculate how much space bubble's naming takes up. + byte_array packed_classifier; + basis::pack(packed_classifier, my_bubble.classifier()); + double classifier_size = packed_classifier.length() - sizeof(int); + // that's how much space is used by our goofy classifier name. there are + // a few bytes extra overhead for packing a string array and we remove + // them from consideration; we only want credit for the name, since that + // is not truly overhead, given that the bubble infoton chose it. + double payload_portion = my_bubble.packed_size() + classifier_size; + // calculate the portion of our transmissions that are solely the + // result of what we are putting into the package. + double overhead = bytes_per_item - payload_portion; + // okay, this is how many bytes per item is cromp noise, rather than + // something the user is responsible for. + double percent_overhead = overhead / bytes_per_item; + +// change 0 to 1 to enable this section of information. +#if 0 + // get additional facts about how much of a packed infoton is wasted. + byte_array packed_infote; + infoton::fast_pack(packed_infote, my_bubble); + log(isprintf("sane? -- overhead for just packed infoton is %d bytes.", + packed_infote.length() - payload_portion)); + octopus_request_id example_request(_uplink->entity(), 23982); + byte_array packed_req_id; + example_request.pack(packed_req_id); + log(isprintf(" -- overhead for octo request id is %d bytes.", + packed_req_id.length())); + byte_array packed_transa; + cromp_transaction::flatten(packed_transa, my_bubble, + octopus_request_id(_uplink->entity(), 23982)); + log(isprintf(" -- overhead for cromp transation is %d bytes.", + packed_transa.length() - payload_portion)); +#endif + + BASE_LOG(isprintf("sent %.0f items, %.0f bytes, %.0f bytes per item,%s" + "payload %.0f bytes, overhead %.0f bytes, percent overhead %.1f%%,%s" + "in %.2f seconds is %f ms/item%s" + "at %.2f %cb/sec & %.2f items/sec.", + bandwidth.number_of_sends(), bandwidth.bytes_sent(), + bytes_per_item, + log_base::platform_ending(), + payload_portion, overhead, percent_overhead * 100.0, + log_base::platform_ending(), + bandwidth.total_time() / SECOND_ms, + bandwidth.total_time() / bandwidth.number_of_sends(), + log_base::platform_ending(), + (bandwidth.kilobytes_per_second() < 1024.0? + bandwidth.kilobytes_per_second() + : bandwidth.megabytes_per_second()), + (bandwidth.kilobytes_per_second() < 1024.0? 'K' : 'M'), + bandwidth.number_of_sends() / (bandwidth.total_time() / SECOND_ms))); +} + +void cromp_client_tester::cause_object_reconstruction() +{ + FUNCDEF("cause_object_reconstruction"); + int rando = chaos().inclusive(1, 100); + if (rando > CHANCE_OF_RECONSTRUCT) return; // not doing it this time. + LOG(istring("reconstructing client at ") + _server_loc.text_form()); +//below is not good when multiple threads are allowed to romp on client. +//// WHACK(_uplink); +//// _uplink = new cromp_client(_server_loc); + + _uplink->disconnect(); + outcome ret = common::INVALID; + int counter = 100; // allowed this many times to try to reconnect. + while ( (ret != common::OKAY) && (counter-- >= 0) ) { + ret = _uplink->connect(); + if (ret != cromp_client::OKAY) { + LOG(istring("couldn't reconnect this time: ") + + cromp_client::outcome_name(ret)); + portable::sleep_ms(420); + } + } +} + +int cromp_client_tester::execute() +{ + FUNCDEF("execute"); + + // testing that crompish pax are done right. + bubble fud(randomizer().inclusive(12, 2829)); + byte_array packed_fud; + fud.pack(packed_fud); + if (packed_fud.length() != fud.packed_size()) + deadly_error(class_name(), func, "bubble's packed size method is wrong."); + + if (_encryption) _uplink->enable_encryption(); + + outcome ret = _uplink->connect(); + if (ret != cromp_client::OKAY) { + deadly_error(class_name(), func, istring("connection failed with error: ") + + cromp_client::outcome_name(ret)); + } + + thread_cabinet cab; // we store a bunch of threads here. + + LOG(isprintf("adding %d grabber threads to test.", _grabber_count)); + + // create the extra grabber threads. + for (int i = 0; i < _grabber_count; i++) { + grabby_thread *to_add = new grabby_thread(*this); + cab.add_thread(to_add, false, NIL); + } + + LOG(isprintf("adding %d transmitter threads to test.", _thread_count)); + + // create the specified number of threads. + for (int j = 0; j < _thread_count; j++) { + bitey_thread *to_add = new bitey_thread(*this); + cab.add_thread(to_add, false, NIL); + } + +//LOG("starting all threads..."); + time_stamp start; + cab.start_all(NIL); +//LOG("done starting threads..."); + + portable::sleep_ms(400); // wait until a few get cranked up. + +//LOG("did our initial sleep..."); + + while (cab.any_running()) { + portable::sleep_ms(30); + if (!_threads_active) { + break; + } +//LOG("main loop..."); + if (time_stamp(-_report_interval) > _last_report) { + report(start, cromp_common::total_bytes_sent() + + cromp_common::total_bytes_received(), + _finished_loops); + _last_report.reset(); + } + if (_reconstruct_object) { + cause_object_reconstruction(); + } + if (!_uplink->connected()) { + LOG("connection dropped. trying to connect again."); + outcome ret = _uplink->connect(); + if (ret != cromp_client::OKAY) { + // snooze a bit so as not to drive server crazy or log too much noise. + portable::sleep_ms(10 * SECOND_ms); + } + } + } + + LOG("- done testing -"); + + if (_finished_loops != double(_thread_count) * _send_count) + LOG(isprintf("number of loops was calculated differently: wanted %d, " + "got %d", _thread_count * _send_count, _finished_loops)); + + report(start, cromp_common::total_bytes_sent() + + cromp_common::total_bytes_received(), + _thread_count * _send_count); + +//LOG("stopping all threads..."); + cab.stop_all(); + LOG("all threads exited."); + +#ifdef DEBUG_TESTER +/// LOG("hit a key to continue..."); +/// int char_read = fgetc(stdin); +#endif + + BASE_LOG("cromp_client:: works for those functions tested."); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// + +HOOPLE_MAIN(cromp_client_tester, ) + diff --git a/octopi/library/tests_cromp/test_cromp_server.cpp b/octopi/library/tests_cromp/test_cromp_server.cpp new file mode 100644 index 00000000..e2a5da92 --- /dev/null +++ b/octopi/library/tests_cromp/test_cromp_server.cpp @@ -0,0 +1,220 @@ +/*****************************************************************************\ +* * +* Name : test_cromp_server * +* Author : Chris Koeritz * +* * +******************************************************************************* +* 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 "crompish_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG(a) CLASS_EMERGENCY_LOG(program_wide_logger(), a) + +const int REPORTING_INTERVAL = 28 * SECOND_ms; // how often to squawk. + +//const int ACCEPTING_THREADS = 5; +const int ACCEPTING_THREADS = 1; + +// specifies whether to support lazy evaluation by tentacles. +//const bool SUPPORT_BACKGROUNDING = true; +const bool SUPPORT_BACKGROUNDING = false; + +// determines whether the octopus will do immediate evaluation or not. +//const bool IMMEDIATE_EVALUATION = true; +const bool IMMEDIATE_EVALUATION = false; + +//////////////////////////////////////////////////////////////////////////// + +// forward. +class cromp_server_tester; + +class our_cromp_server : public cromp_server +{ +public: + our_cromp_server(cromp_server_tester &parent, const internet_address &addr) + : cromp_server(addr, ACCEPTING_THREADS, IMMEDIATE_EVALUATION), + _parent(parent) {} + + ~our_cromp_server() {} + + IMPLEMENT_CLASS_NAME("our_cromp_server"); + +private: + cromp_server_tester &_parent; +}; + +//////////////////////////////////////////////////////////////////////////// + +class cromp_server_tester : public application_shell +{ +public: + bool _saw_clients; // true if we ever got a connection. + + cromp_server_tester(); + ~cromp_server_tester(); + + virtual int execute(); + + IMPLEMENT_CLASS_NAME("cromp_server_tester"); + +private: + our_cromp_server *_uplink; + // provides the connection and transmission services. + bool _leave_when_no_clients; // true if we should just do one run. + bool _encryption; // true if we should do an encrypted connection. + internet_address c_address; +}; + +//////////////////////////////////////////////////////////////////////////// + +class real_bubbles_tentacle : public bubbles_tentacle +{ +public: + real_bubbles_tentacle(cromp_server_tester &parent, bool backgrounding) + : bubbles_tentacle(backgrounding), _parent(parent) {} + + virtual outcome consume(infoton &to_chow, const octopus_request_id &item_id, + byte_array &transformed) + { + transformed.reset(); + _parent._saw_clients = true; // we saw someone. +//LOG("got to our cromp's bubble tentacle."); + bubble *inf = dynamic_cast(&to_chow); + if (!inf) return NO_HANDLER; +//LOG("caching product! success getting unpacked etc."); + bubble *junk = (bubble *)inf->clone(); + store_product(junk, item_id); + return OKAY; + } + +private: + cromp_server_tester &_parent; +}; + +//////////////////////////////////////////////////////////////////////////// + +cromp_server_tester::cromp_server_tester() +: application_shell("cromp_server_tester"), + _saw_clients(false), + _uplink(NIL), + _leave_when_no_clients(false), + _encryption(false) +{ + FUNCDEF("constructor"); + SET_DEFAULT_COMBO_LOGGER; + LOG(""); + LOG(""); + + command_line args(__argc, __argv); + // check for a port on the command line. + istring port_text; + int port = 5678; + if (args.get_value("port", port_text, false)) { + LOG(istring("using port: ") + port_text); + port = port_text.convert(5678); + } + int posn = 0; + if (args.find("exit", posn)) { + LOG("seeing the 'exit without clients' flag set."); + _leave_when_no_clients = true; + } + +//hmmm:normalize host so this can take either name or IP. + + // check for a hostname on the command line. + istring hostname("local"); + istring host_temp; + if (args.get_value("host", host_temp, false)) { + LOG(istring("using host: ") + host_temp); + hostname = host_temp; + } + strcpy(c_address.hostname, hostname.s()); + +//LOG(istring("here's the command line:") + log_base::platform_ending() + args.text_form()); + + int indy = 0; + if (args.find("encrypt", indy) || (args.find('e', indy)) ) { + // they're saying that we should encrypt the communication. + LOG("turning on encryption."); + _encryption = true; + } + +// tcpip_stack stack; +// machine_uid host = stack.this_host(machine_uid::TCPIP_LOCATION); + c_address.port = port; +// host.native().stuff(internet_address::ADDRESS_SIZE, c_address.ip_address); + LOG("starting cromp_server"); + _uplink = new our_cromp_server(*this, c_address); + _uplink->add_tentacle(new real_bubbles_tentacle(*this, SUPPORT_BACKGROUNDING)); + _uplink->enable_servers(_encryption); +} + +cromp_server_tester::~cromp_server_tester() +{ + WHACK(_uplink); +} + +int cromp_server_tester::execute() +{ + FUNCDEF("execute"); + + time_stamp next_report(REPORTING_INTERVAL); + + while (true) { + // make sure we didn't see our exit condition. + if (!_uplink->clients() && _leave_when_no_clients && _saw_clients) { + LOG("exiting now"); + break; + } + + if (time_stamp() > next_report) { + int client_count = _uplink->clients(); + const char *verb = "are"; + if (client_count == 1) verb = "is"; + const char *ending = "s"; + if (client_count == 1) ending = ""; + LOG(isprintf("There %s %d client%s.", verb, client_count, ending)); + next_report.reset(REPORTING_INTERVAL); + } + +// new test case; rip out server while still possibly connected. +if (randomizer().inclusive(1, 200) == 32) { +LOG("tearing down entire server and re-creating."); +WHACK(_uplink); +_uplink = new our_cromp_server(*this, c_address); +_uplink->add_tentacle(new real_bubbles_tentacle(*this, SUPPORT_BACKGROUNDING)); +_uplink->enable_servers(_encryption); +} + + portable::sleep_ms(100); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////// + +HOOPLE_MAIN(cromp_server_tester, ) + diff --git a/octopi/library/tests_cromp/test_many_cromp.cpp b/octopi/library/tests_cromp/test_many_cromp.cpp new file mode 100644 index 00000000..bd64ff71 --- /dev/null +++ b/octopi/library/tests_cromp/test_many_cromp.cpp @@ -0,0 +1,181 @@ +/*****************************************************************************\ +* * +* Name : test_many_cromp * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* Sees how a cromp server does with a large number of connections. * +* * +******************************************************************************* +* 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 "crompish_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DEBUG_TESTER + // uncomment for noisier version. + +const int REPORTING_INTERVAL = 20 * SECOND_ms; + // how frequently we tell about bad crompers. + +#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s) +#define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger(), s) + +class many_cromp_tester : public application_shell +{ +public: + many_cromp_tester(); + ~many_cromp_tester(); + + virtual int execute(); + + IMPLEMENT_CLASS_NAME("many_cromp_tester"); + +private: + amorph _uplinks; // a list of cromp clients. + bool _encryption; // true if we're encrypting. + int _count; // number of cromps. +}; + +//////////////////////////////////////////////////////////////////////////// + +many_cromp_tester::many_cromp_tester() +: application_shell("many_cromp_tester"), + _uplinks(), + _encryption(false), + _count(1) +{ + FUNCDEF("constructor"); + LOG(""); + LOG(""); + + internet_address server_loc; + + command_line args(__argc, __argv); +//LOG(isprintf("argc is %d and first is %s", __argc, __argv[0])); + + // check for a port on the command line. + istring port_text; + int port = 5678; + if (args.get_value("port", port_text, false)) { + LOG(istring("using port: ") + port_text); + port = port_text.convert(5678); + } + server_loc.port = port; + + istring count_text; + if (args.get_value("count", count_text, false)) { + LOG(istring("using count: ") + count_text); + _count = count_text.convert(_count); + } + +//hmmm: normalize host so this can take either name or IP. + + int indy = 0; + if (args.find("encrypt", indy, false) + || (args.find('e', indy, false)) ) { + // they're saying that we should encrypt the communication. + _encryption = true; + } + + // check for a hostname on the command line. + istring hostname("local"); + istring host_temp; + if (args.get_value("host", host_temp, false)) { + LOG(istring("using host: ") + host_temp); + hostname = host_temp; + } +LOG(istring("using host: ") + hostname); + strcpy(server_loc.hostname, hostname.s()); + +LOG(istring("opening at ") + server_loc.text_form()); + +LOG(isprintf("count of %d cromps will be created.", _count)); + + for (int i = 0; i < _count; i++) { +LOG(isprintf("%d. A", i)); + cromp_client *uplink = new cromp_client(server_loc); +LOG(isprintf("%d. B", i)); + uplink->add_tentacle(new bubbles_tentacle(false)); +LOG(isprintf("%d. C", i)); + _uplinks.append(uplink); + } + +} + +many_cromp_tester::~many_cromp_tester() +{ +} + +int many_cromp_tester::execute() +{ + FUNCDEF("execute"); + + if (_encryption) { + for (int i = 0; i < _uplinks.elements(); i++) { + _uplinks.borrow(i)->enable_encryption(); + } + } + + for (int i = 0; i < _uplinks.elements(); i++) { + outcome ret = _uplinks.borrow(i)->connect(); + if (ret != cromp_client::OKAY) { + deadly_error(class_name(), func, istring("connection failed with error: ") + + cromp_client::outcome_name(ret)); + } + } + +time_stamp when_to_leave(10 * HOUR_ms); + + time_stamp next_report(REPORTING_INTERVAL); + + while (time_stamp() < when_to_leave) { + int unconnected = 0; + for (int i = 0; i < _uplinks.elements(); i++) { + if (!_uplinks.borrow(i)->connected()) + unconnected++; + } + + if (time_stamp() > next_report) { + int connected = _uplinks.elements() - unconnected; + LOG(isprintf("[ %d connected and %d did not ]", connected, unconnected)); + next_report.reset(REPORTING_INTERVAL); + } + +//do something with uplinks. + + portable::sleep_ms(100); + } + + + BASE_LOG("many cromp_client:: works for those functions tested."); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// + +HOOPLE_MAIN(many_cromp_tester, ) + diff --git a/octopi/library/tests_cromp/version.ini b/octopi/library/tests_cromp/version.ini new file mode 100644 index 00000000..4cf4fbc2 --- /dev/null +++ b/octopi/library/tests_cromp/version.ini @@ -0,0 +1,6 @@ +[version] +description=CROMP Entity Decoder +root=cromp_decoder +name=CROMP Decoder +extension=exe + diff --git a/octopi/library/tests_octopus/t_bin.cpp b/octopi/library/tests_octopus/t_bin.cpp deleted file mode 100644 index 74c85090..00000000 --- a/octopi/library/tests_octopus/t_bin.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/*****************************************************************************\ -* * -* 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(NULL_POINTER); - } - } - 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(NULL_POINTER); - } - 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(NULL_POINTER); - } - 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(NULL_POINTER); - } - 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 deleted file mode 100644 index e939c9b9..00000000 --- a/octopi/library/tests_octopus/t_bin_threaded.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/*****************************************************************************\ -* * -* 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 = NULL_POINTER; - 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(NULL_POINTER); - } - - 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 deleted file mode 100644 index d9240982..00000000 --- a/octopi/library/tests_octopus/t_entity.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/*****************************************************************************\ -* * -* 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 deleted file mode 100644 index 9deb90a7..00000000 --- a/octopi/library/tests_octopus/t_file_transfer.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/*****************************************************************************\ -* * -* 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 deleted file mode 100644 index eb7dd35f..00000000 --- a/octopi/library/tests_octopus/t_identity.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*****************************************************************************\ -* * -* 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 deleted file mode 100644 index 4ce733b1..00000000 --- a/octopi/library/tests_octopus/t_security.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/*****************************************************************************\ -* * -* 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 = NULL_POINTER; - 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 = NULL_POINTER; // 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 deleted file mode 100644 index 1ad69a8d..00000000 --- a/octopi/library/tests_octopus/t_unpacker.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/*****************************************************************************\ -* * -* 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 = NULL_POINTER; - 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 NULL_POINTER; - } - 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 NULL_POINTER; - } - 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 = NULL_POINTER; - _addron = NULL_POINTER; - } - - 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 = NULL_POINTER; -//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, ) - diff --git a/octopi/library/tests_octopus/test_bin.cpp b/octopi/library/tests_octopus/test_bin.cpp new file mode 100644 index 00000000..74c85090 --- /dev/null +++ b/octopi/library/tests_octopus/test_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(NULL_POINTER); + } + } + 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(NULL_POINTER); + } + 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(NULL_POINTER); + } + 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(NULL_POINTER); + } + 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/test_bin_threaded.cpp b/octopi/library/tests_octopus/test_bin_threaded.cpp new file mode 100644 index 00000000..e939c9b9 --- /dev/null +++ b/octopi/library/tests_octopus/test_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 = NULL_POINTER; + 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(NULL_POINTER); + } + + 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/test_entity.cpp b/octopi/library/tests_octopus/test_entity.cpp new file mode 100644 index 00000000..d9240982 --- /dev/null +++ b/octopi/library/tests_octopus/test_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/test_file_transfer.cpp b/octopi/library/tests_octopus/test_file_transfer.cpp new file mode 100644 index 00000000..9deb90a7 --- /dev/null +++ b/octopi/library/tests_octopus/test_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/test_identity.cpp b/octopi/library/tests_octopus/test_identity.cpp new file mode 100644 index 00000000..eb7dd35f --- /dev/null +++ b/octopi/library/tests_octopus/test_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/test_security.cpp b/octopi/library/tests_octopus/test_security.cpp new file mode 100644 index 00000000..4ce733b1 --- /dev/null +++ b/octopi/library/tests_octopus/test_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 = NULL_POINTER; + 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 = NULL_POINTER; // 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/test_unpacker.cpp b/octopi/library/tests_octopus/test_unpacker.cpp new file mode 100644 index 00000000..1ad69a8d --- /dev/null +++ b/octopi/library/tests_octopus/test_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 = NULL_POINTER; + 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 NULL_POINTER; + } + 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 NULL_POINTER; + } + 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 = NULL_POINTER; + _addron = NULL_POINTER; + } + + 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 = NULL_POINTER; +//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, ) +