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.
tentacles \
cromp \
synchronic \
- tests_sockets
-
-# tests_octopus
+ tests_cromp \
+ tests_octopus \
+ tests_sockets
include rules.def
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/istring.h>
+#include <cromp/cromp_common.h>
+#include <octopus/entity_defs.h>
+#include <opsystem/application_shell.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <data_struct/static_memory_gremlin.h>
+#include <sockets/machine_uid.h>
+#include <textual/byte_format.h>
+
+#include <stdio.h>
+
+#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, )
+
--- /dev/null
+#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 <basis/chaos.h>
+#include <basis/string_array.h>
+#include <cromp/cromp_transaction.h>
+#include <geometric/screen_rectangle.h>
+#include <octopus/infoton.h>
+#include <octopus/tentacle_helper.h>
+
+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<bubble>(*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<bubble>
+{
+public:
+ bubbles_tentacle(bool backgrounded)
+ : tentacle_helper<bubble>(bubble().classifier(), backgrounded)
+ {}
+};
+
+#endif
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/chaos.h>
+#include <basis/istring.h>
+#include <basis/portable.h>
+#include <basis/set.h>
+#include <cromp/cromp_client.h>
+#include <mechanisms/ithread.h>
+#include <mechanisms/thread_cabinet.h>
+#include <mechanisms/throughput_counter.h>
+#include <octopus/entity_data_bin.h>
+#include <octopus/entity_defs.h>
+#include <octopus/infoton.h>
+#include <opsystem/application_shell.h>
+#include <opsystem/command_line.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <opsystem/filename.h>
+#include <opsystem/rendezvous.h>
+#include <data_struct/static_memory_gremlin.h>
+#include <sockets/address.h>
+
+#include <stdlib.h>
+
+#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<octopus_request_id> &ids,
+ basis::set<octopus_request_id> &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<octopus_request_id> &ids,
+ basis::set<octopus_request_id> &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<octopus_request_id> _ids; // the ids for commands we've sent.
+ basis::set<octopus_request_id> _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<octopus_request_id> &ids,
+ basis::set<octopus_request_id> &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<bubble *>(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<octopus_request_id> &ids,
+ basis::set<octopus_request_id> &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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/byte_array.h>
+#include <basis/function.h>
+#include <basis/istring.h>
+#include <basis/log_base.h>
+#include <basis/portable.h>
+#include <cromp/cromp_server.h>
+#include <mechanisms/time_stamp.h>
+#include <octopus/tentacle.h>
+#include <opsystem/application_shell.h>
+#include <opsystem/command_line.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <data_struct/static_memory_gremlin.h>
+#include <sockets/address.h>
+#include <sockets/machine_uid.h>
+#include <sockets/tcpip_stack.h>
+
+#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<bubble *>(&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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/chaos.h>
+#include <basis/istring.h>
+#include <basis/portable.h>
+#include <data_struct/amorph.h>
+#include <cromp/cromp_client.h>
+#include <octopus/entity_defs.h>
+#include <octopus/infoton.h>
+#include <opsystem/application_shell.h>
+#include <opsystem/command_line.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <data_struct/static_memory_gremlin.h>
+#include <sockets/address.h>
+
+#include <stdio.h>
+
+#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<cromp_client> _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, )
+
--- /dev/null
+[version]
+description=CROMP Entity Decoder
+root=cromp_decoder
+name=CROMP Decoder
+extension=exe
+
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <application/hoople_main.h>
-#include <basis/byte_array.h>
-#include <mathematics/chaos.h>
-#include <basis/functions.h>
-#include <basis/guards.h>
-#include <basis/astring.h>
-#include <application/application_shell.h>
-#include <loggers/console_logger.h>
-#include <loggers/program_wide_logger.h>
-#include <structures/static_memory_gremlin.h>
-#include <octopus/entity_data_bin.h>
-#include <octopus/entity_defs.h>
-#include <tentacles/security_infoton.h>
-#include <textual/string_manipulation.h>
-
-#include <stdio.h>
-
-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<octopus_request_id> 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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <application/hoople_main.h>
-#include <basis/byte_array.h>
-#include <mathematics/chaos.h>
-#include <basis/functions.h>
-#include <basis/guards.h>
-#include <basis/astring.h>
-#include <basis/mutex.h>
-#include <structures/amorph.h>
-#include <structures/static_memory_gremlin.h>
-#include <loggers/console_logger.h>
-#include <processes/ethread.h>
-#include <processes/safe_roller.h>
-#include <timely/time_control.h>
-#include <timely/time_stamp.h>
-#include <octopus/entity_data_bin.h>
-#include <octopus/entity_defs.h>
-#include <octopus/unhandled_request.h>
-#include <application/application_shell.h>
-#include <configuration/application_configuration.h>
-#include <textual/string_manipulation.h>
-
-#include <stdio.h>
-
-#ifdef __WIN32__
- #include <process.h>
-#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<ethread> 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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <basis/byte_array.h>
-#include <mathematics/chaos.h>
-#include <basis/guards.h>
-#include <basis/astring.h>
-#include <octopus/entity_defs.h>
-#include <application/application_shell.h>
-#include <loggers/console_logger.h>
-#include <loggers/file_logger.h>
-#include <structures/static_memory_gremlin.h>
-#include <sockets/tcpip_stack.h>
-#include <textual/string_manipulation.h>
-
-#ifdef __WIN32__
- #include <process.h>
-#else
- #include <unistd.h>
-#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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <basis/functions.h>
-#include <structures/string_array.h>
-#include <structures/static_memory_gremlin.h>
-#include <loggers/console_logger.h>
-#include <application/application_shell.h>
-#include <tentacles/file_transfer_tentacle.h>
-#include <tentacles/recursive_file_copy.h>
-
-#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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <basis/astring.h>
-#include <octopus/entity_defs.h>
-#include <octopus/identity_infoton.h>
-#include <octopus/infoton.h>
-#include <octopus/octopus.h>
-#include <octopus/tentacle.h>
-#include <application/application_shell.h>
-#include <loggers/console_logger.h>
-#include <structures/static_memory_gremlin.h>
-
-//////////////
-
-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<identity_infoton *>(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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <basis/astring.h>
-#include <basis/mutex.h>
-#include <structures/static_memory_gremlin.h>
-#include <octopus/entity_defs.h>
-#include <octopus/infoton.h>
-#include <octopus/octopus.h>
-#include <octopus/tentacle.h>
-#include <application/application_shell.h>
-#include <loggers/console_logger.h>
-#include <structures/static_memory_gremlin.h>
-#include <sockets/internet_address.h>
-#include <tentacles/login_tentacle.h>
-#include <tentacles/simple_entity_registry.h>
-
-//////////////
-
-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, )
-
+++ /dev/null
-/*****************************************************************************\
-* *
-* 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 <basis/astring.h>
-#include <structures/static_memory_gremlin.h>
-#include <octopus/entity_defs.h>
-#include <octopus/infoton.h>
-#include <octopus/octopus.h>
-#include <octopus/tentacle_helper.h>
-#include <application/application_shell.h>
-#include <loggers/console_logger.h>
-#include <loggers/file_logger.h>
-#include <structures/static_memory_gremlin.h>
-#include <sockets/internet_address.h>
-
-//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<address_ton>
-{
-public:
- address_chomper()
- : tentacle_helper<address_ton>(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<address_ton *>(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, )
-
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <application/hoople_main.h>
+#include <basis/byte_array.h>
+#include <mathematics/chaos.h>
+#include <basis/functions.h>
+#include <basis/guards.h>
+#include <basis/astring.h>
+#include <application/application_shell.h>
+#include <loggers/console_logger.h>
+#include <loggers/program_wide_logger.h>
+#include <structures/static_memory_gremlin.h>
+#include <octopus/entity_data_bin.h>
+#include <octopus/entity_defs.h>
+#include <tentacles/security_infoton.h>
+#include <textual/string_manipulation.h>
+
+#include <stdio.h>
+
+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<octopus_request_id> 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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <application/hoople_main.h>
+#include <basis/byte_array.h>
+#include <mathematics/chaos.h>
+#include <basis/functions.h>
+#include <basis/guards.h>
+#include <basis/astring.h>
+#include <basis/mutex.h>
+#include <structures/amorph.h>
+#include <structures/static_memory_gremlin.h>
+#include <loggers/console_logger.h>
+#include <processes/ethread.h>
+#include <processes/safe_roller.h>
+#include <timely/time_control.h>
+#include <timely/time_stamp.h>
+#include <octopus/entity_data_bin.h>
+#include <octopus/entity_defs.h>
+#include <octopus/unhandled_request.h>
+#include <application/application_shell.h>
+#include <configuration/application_configuration.h>
+#include <textual/string_manipulation.h>
+
+#include <stdio.h>
+
+#ifdef __WIN32__
+ #include <process.h>
+#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<ethread> 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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/byte_array.h>
+#include <mathematics/chaos.h>
+#include <basis/guards.h>
+#include <basis/astring.h>
+#include <octopus/entity_defs.h>
+#include <application/application_shell.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <structures/static_memory_gremlin.h>
+#include <sockets/tcpip_stack.h>
+#include <textual/string_manipulation.h>
+
+#ifdef __WIN32__
+ #include <process.h>
+#else
+ #include <unistd.h>
+#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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/functions.h>
+#include <structures/string_array.h>
+#include <structures/static_memory_gremlin.h>
+#include <loggers/console_logger.h>
+#include <application/application_shell.h>
+#include <tentacles/file_transfer_tentacle.h>
+#include <tentacles/recursive_file_copy.h>
+
+#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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/astring.h>
+#include <octopus/entity_defs.h>
+#include <octopus/identity_infoton.h>
+#include <octopus/infoton.h>
+#include <octopus/octopus.h>
+#include <octopus/tentacle.h>
+#include <application/application_shell.h>
+#include <loggers/console_logger.h>
+#include <structures/static_memory_gremlin.h>
+
+//////////////
+
+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<identity_infoton *>(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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/astring.h>
+#include <basis/mutex.h>
+#include <structures/static_memory_gremlin.h>
+#include <octopus/entity_defs.h>
+#include <octopus/infoton.h>
+#include <octopus/octopus.h>
+#include <octopus/tentacle.h>
+#include <application/application_shell.h>
+#include <loggers/console_logger.h>
+#include <structures/static_memory_gremlin.h>
+#include <sockets/internet_address.h>
+#include <tentacles/login_tentacle.h>
+#include <tentacles/simple_entity_registry.h>
+
+//////////////
+
+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, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* 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 <basis/astring.h>
+#include <structures/static_memory_gremlin.h>
+#include <octopus/entity_defs.h>
+#include <octopus/infoton.h>
+#include <octopus/octopus.h>
+#include <octopus/tentacle_helper.h>
+#include <application/application_shell.h>
+#include <loggers/console_logger.h>
+#include <loggers/file_logger.h>
+#include <structures/static_memory_gremlin.h>
+#include <sockets/internet_address.h>
+
+//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<address_ton>
+{
+public:
+ address_chomper()
+ : tentacle_helper<address_ton>(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<address_ton *>(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, )
+