--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unit_tests/bundle-protocol-test.cc Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,579 @@
+/*
+ * Copyright 2004-2006 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <dtn-config.h>
+#endif
+
+#include <oasys/util/UnitTest.h>
+
+#include "bundling/Bundle.h"
+#include "bundling/BundleProtocol.h"
+#include "bundling/UnknownBlockProcessor.h"
+#include "storage/BundleStore.h"
+#include "storage/DTNStorageConfig.h"
+
+using namespace oasys;
+using namespace dtn;
+
+Bundle*
+new_bundle()
+{
+ static int next_bundleid = 10;
+
+ Bundle* b = new Bundle(oasys::Builder::builder());
+ b->test_set_bundleid(next_bundleid++);
+ b->set_is_fragment(false);
+ b->set_is_admin(false);
+ b->set_do_not_fragment(false);
+ b->set_in_datastore(false);
+ b->set_custody_requested(false);
+ b->set_local_custody(false);
+ b->set_singleton_dest(true);
+ b->set_priority(0);
+ b->set_receive_rcpt(false);
+ b->set_custody_rcpt(false);
+ b->set_forward_rcpt(false);
+ b->set_delivery_rcpt(false);
+ b->set_deletion_rcpt(false);
+ b->set_app_acked_rcpt(false);
+ b->set_orig_length(0);
+ b->set_frag_offset(0);
+ b->set_expiration(0);
+ b->set_owner("");
+ b->set_creation_ts(BundleTimestamp(0,0));
+ b->mutable_payload()->init(b->bundleid());
+ return b;
+}
+
+#define ONE_CHUNK 1
+#define ONEBYTE_CHUNKS 2
+#define RANDOM_CHUNKS 3
+
+int
+protocol_test(Bundle* b1, int chunks)
+{
+#define AVG_CHUNK 16
+
+ u_char payload1[32768];
+ u_char payload2[32768];
+ u_char buf[32768];
+ int encode_len, decode_len;
+ int errno_; const char* strerror_;
+
+ Bundle* b2;
+
+ LinkRef link("protocol_test");
+ BlockInfoVec* blocks = BundleProtocol::prepare_blocks(b1, link);
+ encode_len = BundleProtocol::generate_blocks(b1, blocks, link);
+
+ bool complete = false;
+ int produce_len = 0;
+ do {
+ size_t chunk_size;
+ switch(chunks) {
+ case ONE_CHUNK:
+ chunk_size = encode_len;
+ ASSERT(encode_len < (int)sizeof(buf));
+ break;
+
+ case ONEBYTE_CHUNKS:
+ chunk_size = 1;
+ break;
+
+ case RANDOM_CHUNKS:
+ chunk_size = oasys::Random::rand(AVG_CHUNK);
+ break;
+
+ default:
+ NOTREACHED;
+ }
+
+ size_t cc = BundleProtocol::produce(b1, blocks,
+ &buf[produce_len],
+ produce_len,
+ chunk_size,
+ &complete);
+
+ ASSERT((cc == chunk_size) || complete);
+ produce_len += cc;
+ ASSERT(produce_len <= encode_len);
+ } while (!complete);
+
+ ASSERT(produce_len == encode_len);
+ CHECK(encode_len > 0);
+
+ // extract the payload before we swing the payload directory
+ b1->payload().read_data(0, b1->payload().length(), payload1);
+
+ b2 = new_bundle();
+
+ complete = false;
+ decode_len = 0;
+ do {
+ size_t chunk_size;
+ switch(chunks) {
+ case ONE_CHUNK:
+ chunk_size = encode_len;
+ ASSERT(encode_len < (int)sizeof(buf));
+ break;
+
+ case ONEBYTE_CHUNKS:
+ chunk_size = 1;
+ break;
+
+ case RANDOM_CHUNKS:
+ chunk_size = oasys::Random::rand(AVG_CHUNK);
+ break;
+
+ default:
+ NOTREACHED;
+ }
+
+ int cc = BundleProtocol::consume(b2,
+ &buf[decode_len],
+ chunk_size,
+ &complete);
+
+ ASSERT((cc == (int)chunk_size) || complete);
+ decode_len += cc;
+ ASSERT(decode_len <= encode_len);
+ } while (!complete);
+
+ CHECK_EQUAL(decode_len, encode_len);
+
+ CHECK_EQUALSTR(b1->source().c_str(), b2->source().c_str());
+ CHECK_EQUALSTR(b1->dest().c_str(), b2->dest().c_str());
+ CHECK_EQUALSTR(b1->custodian().c_str(), b2->custodian().c_str());
+ CHECK_EQUALSTR(b1->replyto().c_str(), b2->replyto().c_str());
+ CHECK_EQUAL(b1->is_fragment(), b2->is_fragment());
+ CHECK_EQUAL(b1->is_admin(), b2->is_admin());
+ CHECK_EQUAL(b1->do_not_fragment(), b2->do_not_fragment());
+ CHECK_EQUAL(b1->custody_requested(), b2->custody_requested());
+ CHECK_EQUAL(b1->priority(), b2->priority());
+ CHECK_EQUAL(b1->receive_rcpt(), b2->receive_rcpt());
+ CHECK_EQUAL(b1->custody_rcpt(), b2->custody_rcpt());
+ CHECK_EQUAL(b1->forward_rcpt(), b2->forward_rcpt());
+ CHECK_EQUAL(b1->delivery_rcpt(), b2->delivery_rcpt());
+ CHECK_EQUAL(b1->deletion_rcpt(), b2->deletion_rcpt());
+ CHECK_EQUAL(b1->creation_ts().seconds_, b2->creation_ts().seconds_);
+ CHECK_EQUAL(b1->creation_ts().seqno_, b2->creation_ts().seqno_);
+ CHECK_EQUAL(b1->expiration(), b2->expiration());
+ CHECK_EQUAL(b1->frag_offset(), b2->frag_offset());
+ CHECK_EQUAL(b1->orig_length(), b2->orig_length());
+ CHECK_EQUAL(b1->payload().length(), b2->payload().length());
+ CHECK_EQUALSTR(b1->sequence_id().to_str(), b2->sequence_id().to_str());
+ CHECK_EQUALSTR(b1->obsoletes_id().to_str(), b2->obsoletes_id().to_str());
+
+ b2->payload().read_data(0, b2->payload().length(), payload2);
+
+ bool payload_ok = true;
+ for (u_int i = 0; i < b2->payload().length(); ++i) {
+ if (payload1[i] != payload2[i]) {
+ log_err_p("/test", "payload mismatch at byte %d: 0x%x != 0x%x",
+ i, payload1[i], payload2[i]);
+ payload_ok = false;
+ }
+ }
+ CHECK(payload_ok);
+
+ // check extension blocks
+ b1->lock()->lock("protocol_test");
+ if (b1->recv_blocks().size() != 0)
+ {
+ for (BlockInfoVec::const_iterator iter = b1->recv_blocks().begin();
+ iter != b1->recv_blocks().end();
+ ++iter)
+ {
+ if (iter->type() == BundleProtocol::PRIMARY_BLOCK ||
+ iter->type() == BundleProtocol::PAYLOAD_BLOCK)
+ {
+ continue;
+ }
+
+ const BlockInfo* block1 = &*iter;
+ const BlockInfo* block2 = b2->recv_blocks().find_block(iter->type());
+
+ CHECK_EQUAL(block1->type(), block2->type());
+
+ u_int64_t flags1 = block1->flags();
+ u_int64_t flags2 = block2->flags();
+ CHECK((flags2 & BundleProtocol::BLOCK_FLAG_FORWARDED_UNPROCESSED) != 0);
+ flags2 &= ~BundleProtocol::BLOCK_FLAG_FORWARDED_UNPROCESSED;
+ CHECK_EQUAL_U64(flags1, flags2);
+
+ CHECK_EQUAL(block1->eid_list().size(), block2->eid_list().size());
+ for (size_t i = 0; i < block1->eid_list().size(); ++i) {
+ CHECK_EQUALSTR(block1->eid_list()[i].str(),
+ block2->eid_list()[i].str());
+ }
+
+ CHECK_EQUAL(block1->data_length(), block2->data_length());
+ const u_char* contents1 = block1->contents().buf() + block1->data_offset();
+ const u_char* contents2 = block2->contents().buf() + block2->data_offset();
+ bool contents_ok = true;
+
+ for (u_int i = 0; i < block1->data_length(); ++i) {
+ if (contents1[i] != contents2[i]) {
+ log_err_p("/test", "extension block mismatch at byte %d: "
+ "0x%x != 0x%x",
+ i, contents1[i], contents2[i]);
+ contents_ok = false;
+ }
+ }
+ CHECK(contents_ok);
+ }
+ }
+ b1->lock()->unlock();
+
+ delete b1;
+ delete b2;
+
+ return UNIT_TEST_PASSED;
+}
+
+DECLARE_TEST(Init) {
+ BundleProtocol::init_default_processors();
+ return UNIT_TEST_PASSED;
+}
+
+#define DECLARE_BP_TESTS(_what) \
+DECLARE_TEST(_what ## OneChunk) { \
+ return protocol_test(init_ ## _what (), ONE_CHUNK); \
+} \
+ \
+DECLARE_TEST(_what ## OneByteChunks) { \
+ return protocol_test(init_ ## _what (), ONEBYTE_CHUNKS); \
+} \
+ \
+DECLARE_TEST(_what ## RandomChunks) { \
+ return protocol_test(init_ ## _what (), RANDOM_CHUNKS); \
+} \
+
+#define ADD_BP_TESTS(_what) \
+ADD_TEST(_what ## OneChunk); \
+ADD_TEST(_what ## OneByteChunks); \
+ADD_TEST(_what ## RandomChunks);
+
+Bundle* init_Basic()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+ bundle->set_expiration(1000);
+ bundle->set_creation_ts(BundleTimestamp(10101010, 44556677));
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(Basic);
+
+Bundle* init_Fragment()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://frag.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+
+ bundle->set_expiration(30);
+ bundle->set_is_fragment(1);
+ bundle->set_frag_offset(123456789);
+ bundle->set_orig_length(1234567890);
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(Fragment);
+
+Bundle* init_AllFlags()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+
+ bundle->set_is_admin(true);
+ bundle->set_do_not_fragment(true);
+ bundle->set_custody_requested(true);
+ bundle->set_priority(3);
+ bundle->set_receive_rcpt(true);
+ bundle->set_custody_rcpt(true);
+ bundle->set_forward_rcpt(true);
+ bundle->set_delivery_rcpt(true);
+ bundle->set_deletion_rcpt(true);
+
+ bundle->set_expiration(1000);
+ bundle->set_creation_ts(BundleTimestamp(10101010, 44556677));
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(AllFlags);
+
+Bundle* init_RandomPayload()
+{
+ Bundle* bundle = new_bundle();
+
+ u_char payload[4096];
+ for (u_int i = 0; i < sizeof(payload); ++i) {
+ payload[i] = oasys::Random::rand(26) + 'a';
+ }
+ bundle->mutable_payload()->set_data(payload, sizeof(payload));
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(RandomPayload);
+
+Bundle* init_UnknownBlocks()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+
+ // fake some blocks arriving off the wire
+ BlockProcessor* primary_bp =
+ BundleProtocol::find_processor(BundleProtocol::PRIMARY_BLOCK);
+ BlockProcessor* payload_bp =
+ BundleProtocol::find_processor(BundleProtocol::PAYLOAD_BLOCK);
+ BlockProcessor* unknown1_bp = BundleProtocol::find_processor(0xaa);
+ BlockProcessor* unknown2_bp = BundleProtocol::find_processor(0xbb);
+ BlockProcessor* unknown3_bp = BundleProtocol::find_processor(0xcc);
+
+ ASSERT(unknown1_bp == UnknownBlockProcessor::instance());
+ ASSERT(unknown2_bp == UnknownBlockProcessor::instance());
+ ASSERT(unknown3_bp == UnknownBlockProcessor::instance());
+
+ BlockInfoVec* recv_blocks = bundle->mutable_recv_blocks();
+ BlockInfo *primary, *payload, *unknown1, *unknown2, *unknown3;
+
+ // initialize all blocks other than the primary
+ primary = recv_blocks->append_block(primary_bp);
+
+ unknown1 = recv_blocks->append_block(unknown1_bp);
+ const char* contents = "this is an extension block";
+ UnknownBlockProcessor::instance()->
+ init_block(unknown1, recv_blocks, 0xaa, 0x0,
+ (const u_char*)contents, strlen(contents));
+
+ unknown2 = recv_blocks->append_block(unknown2_bp);
+ UnknownBlockProcessor::instance()->
+ init_block(unknown2, recv_blocks, 0xbb,
+ BundleProtocol::BLOCK_FLAG_REPLICATE, 0, 0);
+
+ payload = recv_blocks->append_block(payload_bp);
+ UnknownBlockProcessor::instance()->
+ init_block(payload, recv_blocks,
+ BundleProtocol::PAYLOAD_BLOCK,
+ 0, (const u_char*)"test payload", strlen("test payload"));
+
+ unknown3 = recv_blocks->append_block(unknown3_bp);
+ UnknownBlockProcessor::instance()->
+ init_block(unknown3, recv_blocks, 0xcc,
+ BundleProtocol::BLOCK_FLAG_REPLICATE |
+ BundleProtocol::BLOCK_FLAG_LAST_BLOCK,
+ (const u_char*)contents, strlen(contents));
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(UnknownBlocks);
+
+Bundle* init_BigDictionary()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+
+ // fake some blocks arriving off the wire
+ BlockProcessor* primary_bp =
+ BundleProtocol::find_processor(BundleProtocol::PRIMARY_BLOCK);
+ BlockProcessor* payload_bp =
+ BundleProtocol::find_processor(BundleProtocol::PAYLOAD_BLOCK);
+ BlockProcessor* unknown_bp = BundleProtocol::find_processor(0xaa);
+
+ ASSERT(unknown_bp == UnknownBlockProcessor::instance());
+
+ BlockInfoVec* recv_blocks = bundle->mutable_recv_blocks();
+ BlockInfo *primary, *payload, *unknown;
+
+ primary = recv_blocks->append_block(primary_bp);
+ unknown = recv_blocks->append_block(unknown_bp);
+
+ unknown->add_eid(EndpointID("dtn:none"));
+ unknown->add_eid(EndpointID("dtn://something"));
+ unknown->add_eid(EndpointID("dtn://host.com/bar"));
+ unknown->add_eid(EndpointID("dtn2://other.host.com/bar"));
+ unknown->add_eid(EndpointID("dtn3://www.dtnrg.org/code"));
+ unknown->add_eid(EndpointID("http://www.google.com/"));
+ unknown->add_eid(EndpointID("https://www.yahoo.com/"));
+ unknown->add_eid(EndpointID("smtp://mail.you.com/"));
+ unknown->add_eid(EndpointID("news://news.google.com/"));
+ unknown->add_eid(EndpointID("abcdef:ghijkl"));
+ unknown->add_eid(EndpointID("ghijkl:abcdef"));
+ unknown->add_eid(EndpointID("ghijklxxx:abcdefyyy"));
+
+ const char* contents = "this is an extension block";
+ UnknownBlockProcessor::instance()->
+ init_block(unknown, recv_blocks, 0xaa,
+ BundleProtocol::BLOCK_FLAG_EID_REFS,
+ (const u_char*)contents, strlen(contents));
+
+ payload = recv_blocks->append_block(payload_bp);
+ UnknownBlockProcessor::instance()->
+ init_block(payload, recv_blocks,
+ BundleProtocol::PAYLOAD_BLOCK,
+ BundleProtocol::BLOCK_FLAG_LAST_BLOCK,
+ (const u_char*)"test payload", strlen("test payload"));
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(BigDictionary);
+
+Bundle* init_SequenceID()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+ bundle->set_expiration(1000);
+ bundle->set_creation_ts(BundleTimestamp(10101010, 44556677));
+
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://source.dtn/test"), 1);
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://dest.dtn/test"), 2);
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://other.dtn/test"), 3);
+ bundle->mutable_sequence_id()->add(EndpointID("http://foo.com"), 10);
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(SequenceID);
+
+Bundle* init_ObsoletesID()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+ bundle->set_expiration(1000);
+ bundle->set_creation_ts(BundleTimestamp(10101010, 44556677));
+
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://source.dtn/test"), 1);
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://dest.dtn/test"), 2);
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://other.dtn/test"), 3);
+ bundle->mutable_obsoletes_id()->add(EndpointID("http://foo.com"), 10);
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(ObsoletesID);
+
+Bundle* init_SequenceAndObsoletesID()
+{
+ Bundle* bundle = new_bundle();
+ bundle->mutable_payload()->set_data("test payload");
+
+ bundle->mutable_source()->assign("dtn://source.dtn/test");
+ bundle->mutable_dest()->assign("dtn://dest.dtn/test");
+ bundle->mutable_custodian()->assign("dtn:none");
+ bundle->mutable_replyto()->assign("dtn:none");
+ bundle->set_expiration(1000);
+ bundle->set_creation_ts(BundleTimestamp(10101010, 44556677));
+
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://source.dtn/test"), 1);
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://dest.dtn/test"), 2);
+ bundle->mutable_sequence_id()->add(EndpointID("dtn://other.dtn/test"), 3);
+ bundle->mutable_sequence_id()->add(EndpointID("http://foo.com"), 10);
+
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://source.dtn/test2"), 1);
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://dest.dtn/test"), 3);
+ bundle->mutable_obsoletes_id()->add(EndpointID("dtn://someoneelse.dtn/test"), 10);
+ bundle->mutable_obsoletes_id()->add(EndpointID("http://bar.com"), 10);
+
+ return bundle;
+}
+
+DECLARE_BP_TESTS(SequenceAndObsoletesID);
+
+DECLARE_TESTER(BundleProtocolTest) {
+ ADD_TEST(Init);
+ ADD_BP_TESTS(Basic);
+ ADD_BP_TESTS(Fragment);
+ ADD_BP_TESTS(AllFlags);
+ ADD_BP_TESTS(RandomPayload);
+ ADD_BP_TESTS(UnknownBlocks);
+ ADD_BP_TESTS(BigDictionary);
+ ADD_BP_TESTS(SequenceID);
+ ADD_BP_TESTS(ObsoletesID);
+ ADD_BP_TESTS(SequenceAndObsoletesID);
+
+ // XXX/demmer add tests for malformed / mangled headers, too long
+ // sdnv's, etc
+}
+
+int
+main(int argc, const char** argv)
+{
+ BundleProtocolTest t("bundle protocol test");
+ t.init(argc, argv, true);
+
+ system("rm -rf .bundle-protocol-test");
+ system("mkdir .bundle-protocol-test");
+
+ DTNStorageConfig cfg("", "memorydb", "", "");
+ cfg.init_ = true;
+ cfg.payload_dir_.assign(".bundle-protocol-test");
+ cfg.leave_clean_file_ = false;
+
+ oasys::DurableStore ds("/test/ds");
+ ds.create_store(cfg);
+
+ BundleStore::init(cfg, &ds);
+
+ t.run_tests();
+
+ system("rm -rf .bundle-protocol-test");
+}