You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC

svn commit: r767594 [30/43] - in /incubator/etch/trunk/binding-c/runtime/c: ./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/ project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/ project/test/ project/test/logcli/...

Added: incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_remote.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_remote.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_remote.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_remote.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1198 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you 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. 
+ */ 
+
+/*
+ * test_remote.c
+ * test remote, delivery service, etc.
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_svcobj_masks.h"
+#include "etch_transport.h"  
+#include "etchthread.h"
+#include "etch_stub.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_remote.h"
+#include "etch_defvalufact.h"
+#include "etch_plainmailbox.h"
+#include "etch_plainmboxmgr.h"
+#include "etchmap.h"
+#include "etchlog.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+int init_suite(void)
+{
+    apr_setup();
+    etch_runtime_init(TRUE);
+    return this_setup();
+}
+
+int clean_suite(void)
+{
+    this_teardown();
+    etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+    apr_teardown();
+    return 0;
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE TRUE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+    int result = apr_initialize();
+    if (result == 0)
+    {   result = etch_apr_init();
+        g_apr_mempool = etch_apr_mempool;
+    }
+    if (g_apr_mempool)
+        apr_pool_tag(g_apr_mempool, pooltag);
+    else result = -1;
+    return result;
+}
+
+/*
+ * apr_teardown()
+ * free apache portable runtime environment
+ */
+int apr_teardown(void)
+{
+    if (g_apr_mempool)
+        apr_pool_destroy(g_apr_mempool);
+    g_apr_mempool = NULL;
+    apr_terminate();
+    return 0;
+}
+
+int this_setup()
+{
+    return 0;
+}
+
+int this_teardown()
+{    
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * unit test support
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#define THISTEST_WHO_VALUE 0x5151
+
+#define TEST_MSGID  0x1001
+#define TEST_QDELAYMS 1000
+#define TEST_MBOX_LIFETIME_UNTIL_CLOSE 0
+#define TEST_LIFETIME_ONE_SECOND 1000
+#define TEST_MAXMSGS_ONE 1
+
+unsigned short CLASSID_MY_VF;
+unsigned short CLASSID_MY_VF_VTAB;
+unsigned short CLASSID_MY_VF_IMPL;
+unsigned short CLASSID_MY_REMOTEIMPL;
+unsigned short CLASSID_MY_IMPLBASE;
+unsigned short CLASSID_MY_REMOTEBASE;
+unsigned short CLASSID_MY_RESULT;
+ 
+typedef enum whats
+{ TRANSPORT_MESSAGE = 1, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  BEGIN_CALL, END_CALL
+} whats;
+
+etch_resources*         g_my_resources;
+default_value_factory*  g_my_vf;
+etch_plainmailbox*      g_my_mbox; 
+i_mailbox*              g_my_ibox; 
+etch_plainmailboxmgr*   g_my_mboxmgr;           
+i_delivery_service*     g_my_ds;
+etch_type*              g_mt_foo;
+etch_type*              g_mt_bar;
+
+etch_who*               gds_who;
+int64                   gds_messageid;
+int                     gds_what;
+int                     gds_rtypeid;
+int                     gds_eventval;
+int                     gds_queryval;
+int                     gds_controlval;
+int                     gds_valueval;
+
+i_delivery_service* new_my_delivery_service();
+int my_pmboxmgr_session_notify (etch_plainmailboxmgr*, etch_event*);
+default_value_factory* new_fake_valuefactory();
+char* LOGSRC = "TEST";
+
+
+/**
+ * new_my_resources()
+ * resources map constructor
+ */
+etch_resources* new_my_resources(void* valuefactory)
+{   
+    etch_resources* resx = get_etch_transport_resources(NULL);
+    etch_resources_add(resx, ETCH_RESXKEY_MSGIZER_VALUFACT, valuefactory); 
+    return resx;
+}
+
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+int setup_this_test()
+{
+    CLASSID_MY_VF      = get_dynamic_classid();
+    CLASSID_MY_VF_VTAB = get_dynamic_classid();
+    CLASSID_MY_VF_IMPL = get_dynamic_classid();
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    g_mt_foo = new_static_type(L"foo");
+    g_mt_bar = new_static_type(L"bar");
+
+    g_my_vf = new_fake_valuefactory();  
+    set_etchobj_static_all(g_my_vf);   /* so resources map will not destroy */ 
+
+    /* get resources map populated with transport resources such as thread pools */
+    g_my_resources = new_my_resources(g_my_vf);
+
+    g_my_ds = new_my_delivery_service ();
+
+    /* the ids itm object belongs to the ds transport which is the mailbox manager */
+    g_my_mboxmgr = g_my_ds->transport->thisx;
+    CU_ASSERT_FATAL(is_etch_mailboxmgr(g_my_mboxmgr));
+
+    /* register a new mailbox with the manager */
+    g_my_mbox = new_mailbox (g_my_mboxmgr->imanager, TEST_MSGID, 
+       TEST_QDELAYMS, TEST_MBOX_LIFETIME_UNTIL_CLOSE, TEST_MAXMSGS_ONE);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_mbox);
+    g_my_ibox = g_my_mbox->imailbox;
+    g_my_mboxmgr->session_notify = my_pmboxmgr_session_notify;
+
+    return 0;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+void teardown_this_test()
+{ 
+    if (g_my_mboxmgr)
+        if (g_my_mbox)
+            g_my_mbox->destroy(g_my_mbox);
+
+    if (g_my_resources)  
+    {   /* we did a set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result the map will not destroy it. if we had not done
+         * so, the vf would have been destroyed with the resources map. */
+        g_my_resources->destroy(g_my_resources);   
+    }
+
+    if (g_my_vf) 
+    {   /* we clear the set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result we can then destroy it */
+        clear_etchobj_static_all(g_my_vf);
+        g_my_vf->destroy(g_my_vf);
+    }
+
+    if (g_my_ds) 
+        g_my_ds->destroy(g_my_ds);
+
+    destroy_static_type(g_mt_foo);
+    destroy_static_type(g_mt_bar);
+
+    gds_what  = 0;
+    gds_who   = NULL;
+    g_my_vf   = NULL;
+    g_my_ds   = NULL;
+    g_my_mbox = NULL;
+    g_my_ibox = NULL;
+    g_my_mboxmgr = NULL;  
+
+    g_mt_foo = g_mt_bar = NULL;
+    gds_eventval= gds_queryval = gds_controlval = gds_valueval = 0;
+    g_my_resources = NULL;
+    gds_messageid = 0;  
+    gds_rtypeid = 0;
+
+    etchvf_free_builtins(); 
+}
+
+/* - - - - - - - - - -
+ * mailbox manager
+ * - - - - - - - - - - 
+ */
+
+int my_pmboxmgr_session_notify (etch_plainmailboxmgr* mgr, etch_event* evt)
+{
+    switch(evt->value)
+    {   case ETCHEVT_SESSION_DOWN: pmboxmgr_unregister_all(mgr);
+    }
+    ETCHOBJ_DESTROY(evt);
+    return 0;
+}
+
+
+/* - - - - - - - - - -
+ * remote object
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_remoteobj
+ * xxxx_remote_either
+ * this represents for this test what would be a service remote_server or remote_client in practice.
+ */
+typedef struct my_remoteobj
+{
+    unsigned int    hashkey;  
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;  
+    int  (*destroy)(void*);
+    void*(*clone)  (void*); 
+    obj_gethashkey  get_hashkey;
+    struct objmask* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+    i_xxxx_either* xxxx_either_base;  /* owned server or client */
+    xxxx_remote*   remote_base;       /* owned */
+    void*          either_factory;    /* owned */
+    default_value_factory*  vf;       /* owned by base */
+
+    /* note that the transport interface is accessed via the remote_base */ 
+
+} my_remoteobj;
+
+
+
+/* - - - - - - - - - -
+ * value factory
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_valufactory_impl
+ * value factory instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    unsigned int    hashkey;  
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;  
+    int  (*destroy)(void*);
+    void*(*clone)  (void*); 
+    obj_gethashkey  get_hashkey;
+    struct objmask* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory instance data
+ */
+int destroy_my_valufactory_impl(my_valufactory_impl* impl)
+{
+    if (NULL == impl) return -1;
+    if (impl->refcount > 0 && --impl->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(impl))
+    {
+        /* no custom types to destroy - they are global for this test */
+    }
+
+    return destroy_objectex((objmask*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for our value factory's instance data
+ */
+my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    impl->destroy = destroy_my_valufactory_impl;
+
+    return impl;
+}
+
+
+/**
+ * new_fake_valuefactory()
+ */
+default_value_factory* new_fake_valuefactory()
+{
+    my_valufactory_impl* impl = NULL;
+    etchparentinfo* inheritlist = NULL;
+    const unsigned short classid_vf = get_dynamic_classid_unique(&CLASSID_MY_VF);
+    const unsigned short classid_vf_vtab = get_dynamic_classid_unique(&CLASSID_MY_VF_VTAB);
+
+    g_my_vf = new_default_value_factory(NULL, NULL);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((objmask*)g_my_vf, 2, 1, classid_vf_vtab);
+    inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    g_my_vf->class_id = classid_vf;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (objmask*) impl;
+    g_my_vf->vtab->add_type(g_my_vf, g_mt_foo);
+    g_my_vf->vtab->add_type(g_my_vf, g_mt_bar);
+
+    /* set msgid validator so we can set and retrieve message IDs */
+    etchtype_put_validator(g_mt_foo, builtins._mf__message_id, (objmask*) etchvtor_int64_get(0));
+    etchtype_put_validator(g_mt_bar, builtins._mf__message_id, (objmask*) etchvtor_int64_get(0));
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - -
+ * delivery service
+ * - - - - - - - - - - 
+ */
+
+/**
+ * myds_begincall()
+ * override for i_delivery_service.begin_call().
+ * typedef int (*etch_delivsvc_begincall)(void* thisx, etch_message*, void** out);  
+ * @param msg caller relinquishes on success, retains on failure
+ * @param out mailbox interface returned on success
+ * @return 0 success, or -1 failure. new mailbox return in out parameter.
+ */
+int myds_begincall (i_delivery_service* thisx, etch_message* msg, void** out)
+{
+    etch_int64* msgid = NULL;        
+    assert(out);
+    *out = g_my_ibox;
+    gds_what = BEGIN_CALL;
+    msgid = message_get_id(msg);  
+    gds_messageid = msgid? msgid->value: 0;
+    ETCHOBJ_DESTROY(msg);
+    return 0;
+}
+
+
+/**
+ * myds_endcall()
+ * override for i_delivery_service.end_call().
+ * typedef int (*etch_delvisvc_endcall)(void* thisx, i_mailbox*, etch_type*, void** out); 
+ * message response received. close mailbox and return response.
+ * @param mbox the current mailbox (interface), caller retains.
+ * @param response_type type of the response message, caller retains.
+ * @param out pointer to caller's location to receive the message response object.
+ * @return 0 success, -1 failure. response object returned via out parameter.
+ * @remarks assumed that the reply message and its wrapper are destroyed with the mailbox.
+ */
+int myds_endcall (i_delivery_service* thisx, i_mailbox* mbox, etch_type* rtype, void** out)
+{
+    etch_int32* resultobj = new_int32(CLASSID_MY_RESULT);
+    resultobj->class_id = CLASSID_MY_RESULT;
+    gds_what = END_CALL;
+    gds_rtypeid = rtype->id;
+    assert(out);
+    *out = resultobj; 
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * delivery service i_sessionmessage  
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/* this is the i_delivery_service implementation of i_sessionmessage,
+ * distinct from the transport.session's implementation of i_sessionmessage
+ * which is implemented externally and set via set_session().
+ */
+
+/**
+ * myds_session_message()
+ * override for i_delivery_service.ism.session_message().
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+int myds_session_message (etch_tcp_delivery_service* thisx, etch_who* whofrom, etch_message* msg)
+{
+    ETCHOBJ_DESTROY(msg);
+    return -1;
+}
+
+
+/**
+ * myds_session_control()
+ * override for i_delivery_service.ism.session_control().  
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int myds_session_control (etch_tcp_delivery_service* thisx, etch_event* control, objmask* value)
+{
+    ETCHOBJ_DESTROY(control);
+    ETCHOBJ_DESTROY(value);
+    return -1;
+}
+
+
+/**
+ * myds_session_notify()
+ * override for i_delivery_service.ism.session_notify().
+ * @param evt event, caller relinquishes.
+ */
+int myds_session_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    ETCHOBJ_DESTROY(evt);
+    return -1;
+}
+
+
+/**
+ * myds_session_query()
+ * override for i_delivery_service.ism.session_query().
+ * @param query, caller relinquishes.
+ */
+objmask* myds_session_query (etch_tcp_delivery_service* thisx, objmask* query) 
+{
+    ETCHOBJ_DESTROY(query);
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - -   
+ * delivery service i_transportmessage  
+ * - - - - - - - - - - - - - - - - - -   
+ */
+
+/**
+ * myds_transport_message()
+ * override for i_delivery_service.itm.transport_message().
+ * @param whoto recipient - caller retains 
+ * @param message caller relinquishes on success, retains on failure.  
+ * @return 0 success, -1 error.
+ */
+int myds_transport_message (etch_tcp_delivery_service* thisx, etch_who* whoto, etch_message* msg)
+{  
+    etch_int64* msgid = NULL;        
+    gds_what = TRANSPORT_MESSAGE;
+    gds_who  = whoto;    
+    msgid = message_get_id(msg);  
+    gds_messageid = msgid? msgid->value: 0;
+    ETCHOBJ_DESTROY(msg);
+    return 0;
+}
+
+
+/**
+ * myds_transport_control()
+ * override for i_delivery_service.itm.transport_control()
+ * @param control caller relinquishes.
+ * @param value caller relinquishes.
+ */
+int myds_transport_control (etch_tcp_delivery_service* thisx, etch_event* control, etch_int32* value)
+{
+    assert(control);
+    gds_what = TRANSPORT_CONTROL;
+    gds_controlval = control->value;   
+    gds_valueval   = value? value->value: -1;
+    ETCHOBJ_DESTROY(control);
+    ETCHOBJ_DESTROY(value);                                                        
+    return 0;
+}
+
+
+/**
+ * myds_transport_notify()
+ * override for i_delivery_service.itm.transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int myds_transport_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    assert(evt);
+    gds_what = TRANSPORT_NOTIFY;
+    gds_eventval = evt->value;
+    evt->destroy(evt);
+    return 0;
+}
+
+
+/**
+ * myds_transport_query()
+ * override for i_delivery_service.itm.transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+objmask* myds_transport_query (etch_tcp_delivery_service* thisx, etch_query* query) 
+{
+    etch_int32* resultobj = new_int32(CLASSID_MY_RESULT);
+    resultobj->class_id = CLASSID_MY_RESULT;
+    gds_what = TRANSPORT_QUERY;
+    gds_queryval = query->value;
+    query->destroy(query);
+    return (objmask*) resultobj;
+}
+
+/**
+ * myds_get_session()
+ * override for i_delivery_service.itm.get_session()
+ * i_transportmessage::get_session override.
+ */
+i_sessionmessage* myds_get_session (etch_tcp_delivery_service* thisx) 
+{
+    assert(FALSE);
+    return NULL;
+}
+
+
+/**
+ * myds_set_session()
+ * override for i_delivery_service.itm.set_session()
+ * i_transportmessage::set_session override.
+ */
+void myds_set_session (etch_tcp_delivery_service* thisx, i_sessionmessage* newsession) 
+{
+    assert(FALSE);
+}
+
+
+/* - - - - - - - - - - - - - - -    
+ * delivery service construction
+ * - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * new_my_delivery_service()
+ */
+i_delivery_service* new_my_delivery_service()
+{
+    etch_tcp_connection* nullconnection = NULL;
+    etch_tcp_delivery_service* delsvc = NULL;
+    i_sessionmessage*   ism = NULL;
+    i_transportmessage* itm = NULL;
+    etch_client_factory* impl_factory = new_client_factory (NULL, NULL, NULL);
+
+    i_delivery_service* ids = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+        (etch_factory_params*) impl_factory, nullconnection); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ids);
+
+    delsvc = ids->thisx;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(delsvc);
+    CU_ASSERT_EQUAL_FATAL(is_etch_deliverysvc(delsvc), TRUE);
+
+    ism = ids->ism;
+    itm = ids->itm; 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ism);
+    CU_ASSERT_EQUAL_FATAL(is_etch_sessionmsg(ism), TRUE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itm);
+    CU_ASSERT_EQUAL_FATAL(is_etch_transportmsg(itm), TRUE);
+
+    /* override delivery service i_sessionmessage to implementations herein */
+    ids->begin_call      = delsvc->begin_call      = myds_begincall;
+    ids->end_call        = delsvc->end_call        = myds_endcall;
+    ism->session_message = delsvc->session_message = myds_session_message;
+    ism->session_control = delsvc->session_control = myds_session_control;
+    ism->session_notify  = delsvc->session_notify  = myds_session_notify;
+    ism->session_query   = delsvc->session_query   = myds_session_query;
+
+    /* override delivery service i_transportmessage to implementations herein.
+     * note that we swap out the virtuals, but the not the itm object, which
+     * is the ds transport, which is the mailbox manager's itm. the mailbox
+     * manager owns it and will destroy it when destroyed during destruction  
+     * of the delivery service.
+     */
+    itm->transport_message = delsvc->transport_message = myds_transport_message;
+    itm->transport_control = delsvc->transport_control = myds_transport_control;
+    itm->transport_notify  = delsvc->transport_notify  = myds_transport_notify;
+    itm->transport_query   = delsvc->transport_query   = myds_transport_query;
+    itm->get_session       = delsvc->get_session       = myds_get_session;
+    itm->set_session       = delsvc->set_session       = myds_set_session;
+
+    return ids;
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * remote androgynous object 
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * destroy_my_remoteobj()
+ * destructor for our remote object
+ */
+int destroy_my_remoteobj(my_remoteobj* thisx)
+{
+    ETCHOBJ_DESTROY(thisx->xxxx_either_base);
+    ETCHOBJ_DESTROY(thisx->remote_base);
+    return destroy_objectex((objmask*) thisx);
+}
+
+/**
+ * destroy_my_clientorserver_impl()
+ * destructor for our remoteobj.xxxx_either_base
+ */
+int destroy_my_clientorserver_impl(i_xxxx_either* thisx)
+{
+    etch_free(thisx->iobjsession);
+    return destroy_objectex((objmask*) thisx);
+}
+
+
+/**
+ * new_my_clientorserver_impl()
+ * instatiate my_remoteobj.xxxx_either_base
+ */
+i_xxxx_either* new_my_clientorserver_impl(my_remoteobj* thisx)
+{
+    i_xxxx_either* either_base = (i_xxxx_either*) new_object (sizeof(i_xxxx_either), 
+        ETCHTYPEB_EXESERVERBASE, get_dynamic_classid_unique(&CLASSID_MY_IMPLBASE));
+
+    either_base->destroy = destroy_my_clientorserver_impl;
+
+    either_base->thisx = (objmask*) thisx;
+    
+    {   /* populate as much of xxxx_either_impl as we need */
+        i_objsession* ios = new_default_objsession_interface (thisx);
+        either_base->iobjsession = ios;
+        either_base->_session_control = ios->_session_control; 
+        either_base->_session_notify  = ios->_session_notify; 
+        either_base->_session_query   = ios->_session_query; 
+    }
+
+    return either_base;
+}
+
+
+/**
+ * new_my_remote_base
+ * instantiates remote base.  
+ * @param ids delivery service -- caller retains.
+ * @param vf default value factory -- caller retains. 
+ * @param ixxxx service interface -- caller retains.
+ */
+xxxx_remote* new_my_remote_base (void* thisx, 
+    i_delivery_service* ids, etch_value_factory* vf, objmask* ixxxx)
+{
+    xxxx_remote* remote = new_etch_remote_base (thisx, ETCH_DEFSIZE, 
+        get_dynamic_classid_unique(&CLASSID_MY_REMOTEBASE), ids, vf, ixxxx);
+ 
+    return remote;
+}
+
+
+/**
+ * new_my_remote_client_or_server()
+ * instatiate and return an implementing object for the remote base.
+ */
+my_remoteobj* new_my_remote_client_or_server (void* thisx, i_delivery_service* ids, etch_value_factory* vf)
+{
+    /* for these tests it doesn't matter whether we use obj_type of client or server */
+    my_remoteobj* remoteobj = (my_remoteobj*) new_object (sizeof(my_remoteobj), 
+        ETCHTYPEB_REMOTESERVER, get_dynamic_classid_unique(&CLASSID_MY_REMOTEIMPL)); 
+
+    remoteobj->destroy = destroy_my_remoteobj;
+    remoteobj->remote_base = new_my_remote_base (remoteobj, ids, vf, NULL);
+    remoteobj->xxxx_either_base = new_my_clientorserver_impl(remoteobj);
+
+    return remoteobj;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * unit tests
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_setup()
+ * test instantiation and teardown of test components such as delivery service,
+ * value factory, etc.
+ */
+void test_setup(void)
+{
+    setup_this_test();
+
+    do
+    {  
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_new_message()
+ */
+void test_new_message(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf);  
+
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through etchremote_new_message() */
+        etch_message* newmsg = remote->new_message(remote, g_mt_foo);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(newmsg);
+
+        result = is_equal_types(message_type(newmsg), g_mt_foo);
+        CU_ASSERT_EQUAL(result, TRUE);  
+
+        CU_ASSERT_PTR_EQUAL(newmsg->vf, g_my_vf);
+
+        newmsg->destroy(newmsg);
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_send()
+ */
+void test_send(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, MSGIDVAL = 54321; 
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+ 
+        etch_remote*  remote = myremote->remote_base;
+        etch_message* newmsg = remote->new_message (myremote->remote_base, g_mt_foo);
+        message_set_id (newmsg, new_int64(MSGIDVAL));
+
+        /* this call goes through delivery service.transport_message,
+         * which we overrode to myds_transport_message() above.
+         */
+        result = remote->send (remote, newmsg);  /* send message */
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(TRANSPORT_MESSAGE, gds_what);
+        CU_ASSERT_EQUAL(gds_messageid, MSGIDVAL);
+
+        if (0 != result) /* message was relinquished on send() success */
+            ETCHOBJ_DESTROY(newmsg);
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_begincall()
+ */
+void test_begincall(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, MSGIDVAL = 65432; 
+        i_mailbox* outmbox = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+  
+        etch_remote*  remote = myremote->remote_base;
+        etch_message* newmsg = remote->new_message (myremote->remote_base, g_mt_foo);
+        message_set_id (newmsg, new_int64(MSGIDVAL));
+
+        /* this call goes through delivery service.begin_call,
+         * which we overrode to myds_begincall() above.
+         */
+        result = remote->begin_call (remote, newmsg, &outmbox);
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(BEGIN_CALL, gds_what);
+        CU_ASSERT_EQUAL(gds_messageid, MSGIDVAL);
+        CU_ASSERT_PTR_EQUAL(g_my_ibox, outmbox);
+
+        if (0 != result) /* message was relinquished on begin_call() success */
+            ETCHOBJ_DESTROY(newmsg);
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_endcall()
+ */
+void test_endcall(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0;
+        objmask* resultobj = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+  
+        etch_remote*  remote = myremote->remote_base;
+    
+        /* this call goes through delivery service.end_call,
+         * which we overrode to myds_endcall() above.
+         */
+        result = remote->end_call (remote, g_my_ibox, g_mt_bar, &resultobj);
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(END_CALL, gds_what);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj);
+        CU_ASSERT_EQUAL(resultobj->class_id, CLASSID_MY_RESULT); 
+        CU_ASSERT_EQUAL(g_mt_bar->id, gds_rtypeid); 
+        
+        ETCHOBJ_DESTROY(resultobj);
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_transport_query()
+ */
+void test_transport_query(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISQUERYVAL = 76543;
+        objmask* resultobj = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_query,
+         * which we overrode to myds_transport_query() above.
+         */
+        resultobj = remote->transport_query (remote, new_etch_query(0, THISQUERYVAL));
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj); 
+        CU_ASSERT_EQUAL(resultobj->class_id, CLASSID_MY_RESULT); 
+        CU_ASSERT_EQUAL(TRANSPORT_QUERY, gds_what);
+
+        ETCHOBJ_DESTROY(resultobj);
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_transport_control()
+ */
+void test_transport_control(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISCTLVAL = 87654, THISVALVAL = 98765;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() above.
+         */
+        result = remote->transport_control (remote, new_etch_control(0, THISCTLVAL), new_int32(THISVALVAL));
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, THISCTLVAL);
+        CU_ASSERT_EQUAL(gds_valueval, THISVALVAL);
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_transport_notify()
+ */
+void test_transport_notify(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISEVTVAL = 45678;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_notify,
+         * which we overrode to myds_transport_notify() above.
+         */
+        result = remote->transport_notify (remote, new_etch_event(0, THISEVTVAL));
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_NOTIFY, gds_what);
+        CU_ASSERT_EQUAL(gds_eventval, THISEVTVAL);
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_start_waitup()
+ */
+void test_start_waitup(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISWAITMS = 3000;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() in our ds constuctor 
+         * above. so we're not testing an actual connection waitup, we're testing
+         * that the call reaches delivery service.transport_control(), and that
+         * we can override delivery service.transport_control() at will.
+         */
+
+        result = remote->start_waitup(remote, ETCH_NOWAIT);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, ETCH_NOWAIT);  
+
+        result = remote->start_waitup(remote, THISWAITMS);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(gds_controlval, THISWAITMS);       
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_stop_waitdown()
+ */
+void test_stop_waitdown(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISWAITMS = 3000;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() in our ds constuctor 
+         * above. so we're not testing an actual connection waitdown, we're testing
+         * that the call reaches delivery service.transport_control(), and that
+         * we can override delivery service.transport_control() at will.
+         */
+
+        result = remote->stop_waitdown(remote, ETCH_NOWAIT);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, ETCH_NOWAIT);  
+
+        result = remote->stop_waitdown(remote, THISWAITMS);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(gds_controlval, THISWAITMS);       
+
+        myremote->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    CU_pSuite ps = NULL;
+    g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+    if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+    CU_set_output_filename("../test_remote");
+    ps = CU_add_suite("remote base test suite", init_suite, clean_suite);
+    etch_watch_id = 0; 
+        
+    // THESE TESTS ARE BROKEN
+    // TODO first fix the stub tests per java tests, then redo these tests similarly.
+    //CU_add_test(ps, "test test setup and teardown", test_setup);
+    //CU_add_test(ps, "test remote.new_message", test_new_message);
+    //CU_add_test(ps, "test remote.send", test_send);   
+    //CU_add_test(ps, "test remote.begin_call", test_begincall);   
+    //CU_add_test(ps, "test remote.end_call", test_endcall);   
+    //CU_add_test(ps, "test remote.transport_query", test_transport_query);  
+    //CU_add_test(ps, "test remote.transport_control", test_transport_control);  
+    //CU_add_test(ps, "test remote.transport_notify", test_transport_notify);
+    //CU_add_test(ps, "test remote.start_waitup", test_start_waitup);  
+    //CU_add_test(ps, "test remote.stop_waitdown", test_stop_waitdown);     
+
+    if (g_is_automated_test)    
+        CU_automated_run_tests();    
+    else
+    {   CU_basic_set_mode(CU_BRM_VERBOSE);
+        CU_basic_run_tests();
+    }
+
+    if (!g_is_automated_test) { printf("any key ..."); while(!_getch()); wprintf(L"\n"); }     
+    CU_cleanup_registry();
+    return CU_get_error();
+}
\ No newline at end of file

Added: incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_stub.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_stub.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_stub.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/support/test_stub.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1404 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you 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. 
+ */ 
+
+/*
+ * test_stub.c
+ * test stub, delivery service, etc.
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_svcobj_masks.h"
+#include "etch_transport.h"  
+#include "etchthread.h"
+#include "etch_stub.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_defvalufact.h"
+#include "etch_plainmboxmgr.h"
+#include "etch_transport.h"
+#include "etchmap.h"
+#include "etchlog.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+default_value_factory* new_fake_valuefactory();
+etch_server_factory* new_my_stubparams(xxxx_either_impl*, etch_threadpool* qp, etch_threadpool* fp);
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+int init_suite(void)
+{
+    apr_setup();
+    etch_runtime_init(TRUE);
+    return this_setup();
+}
+
+int clean_suite(void)
+{
+    this_teardown();
+    etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+    apr_teardown();
+    return 0;
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE TRUE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+    int result = apr_initialize();
+    if (result == 0)
+    {   result = etch_apr_init();
+        g_apr_mempool = etch_apr_mempool;
+    }
+    if (g_apr_mempool)
+        apr_pool_tag(g_apr_mempool, pooltag);
+    else result = -1;
+    return result;
+}
+
+/*
+ * apr_teardown()
+ * free apache portable runtime environment
+ */
+int apr_teardown(void)
+{
+    if (g_apr_mempool)
+        apr_pool_destroy(g_apr_mempool);
+    g_apr_mempool = NULL;
+    apr_terminate();
+    return 0;
+}
+
+int this_setup()
+{
+    return 0;
+}
+
+int this_teardown()
+{    
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * unit test support
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#define THISTEST_WHO_VALUE 0x5151
+
+unsigned short CLASSID_MY_VF;
+unsigned short CLASSID_MY_VF_VTAB;
+unsigned short CLASSID_MY_VF_IMPL;
+unsigned short CLASSID_MY_IMPLOBJ;
+unsigned short CLASSID_MY_IMPLBASE;
+
+i_delivery_service* new_my_delivery_service();
+etch_thread* thistest_proxy_threadpool_run (etch_threadpool*, etch_threadproc, void*);
+char* LOGSRC = "TEST";
+ 
+typedef enum whats
+{ TRANSPORT_MESSAGE = 1, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  SESSION_QUERY, SESSION_CONTROL, SESSION_NOTIFY, HOWDY,
+} whats;
+
+etch_resources*         g_my_resources;
+default_value_factory*  g_my_vf;
+i_delivery_service*     g_my_ds;
+i_delivery_service*     g_my_transport; /* alias for g_my_ds */
+etch_tcp_delivery_service* g_my_dsimpl;
+i_xxxx_either*          g_my_iserver;
+etch_threadpool*        g_qpool;
+etch_threadpool*        g_fpool;
+etch_who*               g_who;
+etch_type*              g_mt_howdy;
+etch_type*              g_mt_nogood;
+etch_server_factory*    g_stubparams; 
+int                     g_is_run_on_queued_pool;
+int                     g_is_run_on_free_pool;
+int                     g_stub_errors;
+etch_run                g_real_fpool_run;  /* saved threadpool run procs */
+etch_run                g_real_qpool_run;
+
+etch_who*               gds_who;
+etch_message*           gds_message;   
+etch_int32*             gds_query_result;
+int                     gds_what;
+int                     gds_eventval;
+int                     gds_queryval;
+int                     gds_controlval;
+int                     gds_valueval;
+
+etch_who*               gsv_who;
+etch_message*           gsv_message;   
+etch_int32*             gsv_query_result;
+i_delivery_service*     gsv_ds;
+int                     gsv_what;
+int                     gsv_eventval;    
+int                     gsv_queryval;
+int                     gsv_controlval;
+int                     gsv_valueval;
+
+
+/**
+ * new_my_resources()
+ * resources map constructor
+ */
+etch_resources* new_my_resources(void* valuefactory)
+{   
+    etch_resources* resx = get_etch_transport_resources(NULL);
+    etch_resources_add(resx, ETCH_RESXKEY_MSGIZER_VALUFACT, valuefactory); 
+
+    g_qpool = (etch_threadpool*) etch_resources_get (resx, ETCH_RESXKEY_POOLTYPE_QUEUED); 
+    g_real_qpool_run = g_qpool->run; /* save the real run procedure */
+    g_qpool->run = thistest_proxy_threadpool_run; /* intercept the queued pool run */
+
+    g_fpool = (etch_threadpool*) etch_resources_get (resx, ETCH_RESXKEY_POOLTYPE_FREE); 
+    g_real_fpool_run = g_fpool->run; /* save the real run procedure */
+    g_fpool->run = thistest_proxy_threadpool_run; /* intercept the free pool run */
+
+    return resx;
+}
+
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+int setup_this_test()
+{
+    CLASSID_MY_VF      = get_dynamic_classid();
+    CLASSID_MY_VF_VTAB = get_dynamic_classid();
+    CLASSID_MY_VF_IMPL = get_dynamic_classid();
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    g_my_vf = new_fake_valuefactory();  
+    set_etchobj_static_all(g_my_vf);   /* so resources map will not destroy */ 
+ 
+    /* get resources map populated with transport resources such as thread pools */
+    g_my_resources = new_my_resources(g_my_vf);
+
+    //g_my_ds = new_my_delivery_service ();
+    //g_my_transport = g_my_ds; /* alias */
+   
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE), TRUE);
+    gds_query_result = new_int32(1);
+    gsv_query_result = new_int32(2);
+        
+    //g_my_dsimpl = g_my_ds->thisx;
+    //assert(is_etch_deliverysvc(g_my_dsimpl));
+    //assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    return 0;
+}
+
+
+/**
+ * setup_this_stub()
+ * setup for stub
+ */
+int setup_this_stub(xxxx_either_impl* implobj, unsigned char stubtype, 
+    etch_threadpool* qp, etch_threadpool* fp) 
+{  
+    new_my_stubparams(implobj, qp, fp);  
+ 
+    g_my_ds = new_my_delivery_service ();
+    g_my_transport = g_my_ds; /* alias */
+   
+    g_my_dsimpl = g_my_ds->thisx;
+    assert(is_etch_deliverysvc(g_my_dsimpl));
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    return 0;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+void teardown_this_test()
+{ 
+    if (g_my_resources)  
+    {   /* we did a set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result the map will not destroy it. if we had not done
+         * so, the vf would have been destroyed with the resources map. */
+        g_my_resources->destroy(g_my_resources);   
+    }
+
+    if (g_my_vf) 
+    {   /* we clear the set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result we can then destroy it */
+        clear_etchobj_static_all(g_my_vf);
+        g_my_vf->destroy(g_my_vf);
+    }
+
+    if (g_my_ds) 
+        g_my_ds->destroy(g_my_ds);
+    
+    etch_free(g_stubparams);
+    etch_free(g_my_iserver);
+
+    if (g_who) 
+        g_who->destroy(g_who);
+    if (gds_message)
+        gds_message->destroy(gds_message);
+    if (gds_query_result)
+        gds_query_result->destroy(gds_query_result);
+
+    gds_what  = 0;
+    gds_who   = NULL;
+    g_my_vf   = NULL;
+    g_my_ds   = NULL;
+    g_who     = NULL;
+    g_is_run_on_queued_pool = g_is_run_on_free_pool = g_stub_errors = 0;
+    g_mt_howdy  = g_mt_nogood = NULL;
+    gds_message = NULL;
+    gds_eventval= gds_queryval = gds_controlval = gds_valueval = 0;
+    gds_query_result = NULL;
+    g_my_resources = NULL;
+
+    if (gsv_message)
+        gsv_message->destroy(gsv_message);
+    if (gsv_query_result)
+        gsv_query_result->destroy(gsv_query_result);
+
+    gsv_what  = 0;
+    gsv_who   = NULL;
+    gsv_ds    = NULL;
+    gsv_message = NULL;
+    gsv_eventval= gsv_queryval = gsv_controlval = gsv_valueval = 0;
+    g_my_transport = NULL;
+    gsv_query_result = NULL;
+
+    etchvf_free_builtins(); 
+}
+
+
+/* - - - - - - - - - -
+ * stub implementor
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_implob
+ * xxxx_either_impl with an extra method.
+ * this represents for this test what would be an impl_server or impl_client in practice.
+ */
+typedef struct my_implobj
+{
+    unsigned int    hashkey;  
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;  
+    int  (*destroy)(void*);
+    void*(*clone)  (void*); 
+    obj_gethashkey  get_hashkey;
+    struct objmask* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+    i_xxxx_either*  either_base;  /* owned */
+    objmask*        ixxxx;        /* not owned */
+    xxxx_remote_either* either;   /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* fyi: iobjsession->thisx is my_implobj* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - -
+     * custom instance data and methods  
+     * - - - - - - - - - - - - - - - - -
+     */
+
+    int (*howdy) (struct my_implobj*, i_delivery_service*, etch_who*, etch_message*);
+
+} my_implobj;
+
+
+
+/* - - - - - - - - - -
+ * value factory
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_valufactory_impl
+ * value factory instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    unsigned int    hashkey;  
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;  
+    int  (*destroy)(void*);
+    void*(*clone)  (void*); 
+    obj_gethashkey  get_hashkey;
+    struct objmask* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+	etch_type*      mt_howdy;
+    etch_type*      mt_nogood;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory instance data
+ */
+int destroy_my_valufactory_impl(my_valufactory_impl* impl)
+{
+    if (NULL == impl) return -1;
+    if (impl->refcount > 0 && --impl->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(impl))
+    {
+        destroy_static_type(impl->mt_howdy);
+        destroy_static_type(impl->mt_nogood);
+    }
+
+    return destroy_objectex((objmask*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for our value factory's instance data
+ */
+my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    impl->destroy = destroy_my_valufactory_impl;
+
+    impl->mt_howdy  = new_static_type(L"howdy");
+    impl->mt_nogood = new_static_type(L"nogood");
+    g_mt_howdy  = impl->mt_howdy;
+    g_mt_nogood = impl->mt_nogood;
+
+    return impl;
+}
+
+
+/**
+ * new_fake_valuefactory()
+ */
+default_value_factory* new_fake_valuefactory()
+{
+    my_valufactory_impl* impl = NULL;
+    etchparentinfo* inheritlist = NULL;
+    const unsigned short classid_vf = get_dynamic_classid_unique(&CLASSID_MY_VF);
+    const unsigned short classid_vf_vtab = get_dynamic_classid_unique(&CLASSID_MY_VF_VTAB);
+
+    g_my_vf = new_default_value_factory(NULL, NULL);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((objmask*)g_my_vf, 2, 1, classid_vf_vtab);
+    inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    g_my_vf->class_id = classid_vf;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (objmask*) impl;
+    g_my_vf->vtab->add_type(g_my_vf, impl->mt_howdy);
+    g_my_vf->vtab->add_type(g_my_vf, impl->mt_nogood);
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - -
+ * delivery service
+ * - - - - - - - - - - 
+ */
+
+/**
+ * myds_begincall()
+ * typedef int (*etch_delivsvc_begincall)(void* thisx, etch_message*, void** out);  
+ * @param msg caller relinquishes on success, retains on failure
+ * @param out mailbox interface returned on success
+ * @return 0 success, or -1 failure. new mailbox return in out parameter.
+ */
+int myds_begincall (i_delivery_service* thisx, etch_message* msg, void** out)
+{
+    assert(out);
+    *out = NULL;
+    return -1;
+}
+
+
+/**
+ * myds_endcall()
+ * typedef int (*etch_delvisvc_endcall)(void* thisx, i_mailbox*, etch_type*, void** out); 
+ * message response received. close mailbox and return response.
+ * @param mbox the current mailbox (interface), caller retains.
+ * @param response_type type of the response message, caller retains.
+ * @param out pointer to caller's location to receive the message response object.
+ * @return 0 success, -1 failure. response object returned via out parameter.
+ * @remarks assumed that the reply message and its wrapper are destroyed with the mailbox.
+ */
+int myds_endcall (i_delivery_service* thisx, i_mailbox* mbox, etch_type* rtype, void** out)
+{
+    assert(out);
+    *out = NULL;
+    return -1;
+}
+
+/* - - - - - - - - - - - - - - - - -  
+ * delivery service i_sessionmessage  
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/* this is the delivery service interface implementation of i_sessionmessage,
+ * distinct from the transport.session's implementation of i_sessionmessage
+ * which is implemented externally and set via set_session().
+ */
+
+/**
+ * myds_session_message()
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+int myds_session_message (etch_tcp_delivery_service* thisx, etch_who* whofrom, etch_message* msg)
+{
+    ETCHOBJ_DESTROY(msg);
+    return 0;
+}
+
+
+/**
+ * myds_session_control()
+ * delivery service interface implementation of i_session_message  
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int myds_session_control (etch_tcp_delivery_service* thisx, etch_event* control, objmask* value)
+{
+    ETCHOBJ_DESTROY(control);
+    ETCHOBJ_DESTROY(value);
+    return 0;
+}
+
+
+/**
+ * myds_session_notify()
+ * @param evt event, caller relinquishes.
+ */
+int myds_session_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    ETCHOBJ_DESTROY(evt);
+    return 0;
+}
+
+
+/**
+ * myds_session_query()
+ * @param query, caller relinquishes.
+ */
+objmask* myds_session_query (etch_tcp_delivery_service* thisx, objmask* query) 
+{
+    ETCHOBJ_DESTROY(query);
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - -   
+ * delivery service i_transportmessage  
+ * - - - - - - - - - - - - - - - - - -   
+ */
+
+/**
+ * myds_transport_message()
+ * @param whoto recipient - caller retains 
+ * @param message caller relinquishes on success, retains on failure.  
+ * @return 0 success, -1 error.
+ */
+int myds_transport_message(etch_tcp_delivery_service* thisx, etch_who* whoto, etch_message* msg)
+{  
+    gds_what = TRANSPORT_MESSAGE;
+    gds_who  = whoto;                                                           
+    ETCHOBJ_DESTROY(msg);
+    return 0;
+}
+
+
+/**
+ * myds_transport_control()
+ * @param control caller relinquishes.
+ * @param value caller relinquishes.
+ */
+int myds_transport_control (etch_tcp_delivery_service* thisx, etch_event* control, etch_int32* value)
+{
+    gds_what = TRANSPORT_CONTROL;
+    gds_controlval = control->value;   
+    gds_valueval   = value->value;                                                        
+    return 0;
+}
+
+
+/**
+ * myds_transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int myds_transport_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    gds_what  = TRANSPORT_NOTIFY;
+    gds_eventval = evt->value;
+    return 0;
+}
+
+
+/**
+ * myds_transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+objmask* myds_transport_query (etch_tcp_delivery_service* thisx, etch_query* query) 
+{
+    gds_what  = TRANSPORT_QUERY;
+    gds_queryval = query->value;
+    return 0;
+}
+
+/**
+ * myds_get_session()
+ * i_transportmessage::get_session override.
+ */
+i_sessionmessage* myds_get_session (etch_tcp_delivery_service* thisx) 
+{
+    return thisx->session;
+}
+
+
+/**
+ * myds_set_session()
+ * i_transportmessage::set_session override.
+ */
+void myds_set_session (i_delivery_service* ids, i_sessionmessage* newsession) 
+{
+    /* we override methods in the ids itm. the itm object belongs to the ds transport,
+     * which is the mailbox manager. we need to ensure in the real world that the ds
+     * set_session() takes care of housekeeping similarly to this override.
+     */
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    assert(is_etch_sessionmsg(newsession));
+    assert(tcpds->session == ids->session);
+    if (tcpds->session) 
+    {   assert(is_etch_sessionmsg(tcpds->session));
+        tcpds->session->destroy(tcpds->session);
+    }
+    
+    /* replace delivery service impl's sessionmsng with stub's sesssionmsg */
+    tcpds->session = ids->session = newsession;     
+    assert(is_etch_sessionmsg(tcpds->session));  
+
+    /* we say that the ds owns the session, since even though the session belongs 
+     * to the stub, the ds is expected to destroy the stub, and thus the session 
+     * interface along with it. 
+     */
+    ids->is_session_owned = TRUE;
+}
+
+
+/* - - - - - - - - - - - - - - -    
+ * delivery service construction
+ * - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * new_my_delivery_service()
+ */
+i_delivery_service* new_my_delivery_service()
+{
+    etch_tcp_connection* nullconnection = NULL;
+    etch_tcp_delivery_service* delsvc = NULL;
+    i_sessionmessage*    ism = NULL;
+    i_transportmessage*  itm = NULL;
+
+    i_delivery_service* ids = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+        (etch_factory_params*) g_stubparams, nullconnection); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ids);
+
+    delsvc = ids->thisx;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(delsvc);
+    CU_ASSERT_EQUAL_FATAL(is_etch_deliverysvc(delsvc), TRUE);
+
+    ism = ids->ism;
+    itm = ids->itm; 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ism);
+    CU_ASSERT_EQUAL_FATAL(is_etch_sessionmsg(ism), TRUE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itm);
+    CU_ASSERT_EQUAL_FATAL(is_etch_transportmsg(itm), TRUE);
+
+    /* override delivery service i_sessionmessage to implementations herein */
+    ids->begin_call      = delsvc->begin_call      = myds_begincall;
+    ids->end_call        = delsvc->end_call        = myds_endcall;
+    ism->session_message = delsvc->session_message = myds_session_message;
+    ism->session_control = delsvc->session_control = myds_session_control;
+    ism->session_notify  = delsvc->session_notify  = myds_session_notify;
+    ism->session_query   = delsvc->session_query   = myds_session_query;
+
+    /* override delivery service i_transportmessage to implementations herein.
+     * note that we swap out the virtuals, but the not the itm object, which
+     * is the ds transport, which is the mailbox manager's itm. the mailbox
+     * manager owns it and will destroy it when destroyed during destruction  
+     * of the delivery service.
+     */
+    itm->transport_message = delsvc->transport_message = myds_transport_message;
+    itm->transport_control = delsvc->transport_control = myds_transport_control;
+    itm->transport_notify  = delsvc->transport_notify  = myds_transport_notify;
+    itm->transport_query   = delsvc->transport_query   = myds_transport_query;
+    itm->get_session       = delsvc->get_session       = myds_get_session;
+    itm->set_session       = delsvc->set_session       = myds_set_session;
+
+    return ids;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - -
+ * stub's implementing object
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+/* a stub's object is in practice a server implementation, masked by xxxx_either_impl, 
+ * such as perf_server_impl. the obj_type will be ETCHTYPEB_EXESERVERIMPL -   
+ * which is the type get_session_callbacks_from() recognizes to identify the obj as  
+ * implementing i_objsession. constructors assigning ETCHTYPEB_EXESERVERIMPL are 
+ * new_perf_remote_server() and init_perf_server_impl().
+ * stub.obj becomes this object. the delivery service session is set to the stub.
+ */
+
+#if(0)
+
+CLIENT SIDE
+perf_helper.new_remote_server()
+  remote_server = new_perf_remote_server (NULL, deliverysvc, vf);
+  i_perf_client* myclient = p->client = p->new_client(remote_server);
+  perf_client_stub* client_stub = new_perf_client_stub (p);
+     newstub->stub_base = new_stub (implobj, stubtype, ids, qp, fp);
+        /* set ds session to be stub's i_sessionmessage */
+        ids->itm->set_session (ids->itm, stubbase->isession);
+        /* copy stub implementor's i_objsession to the stub */
+        stubbase->impl_callbacks = etchstub_get_session_callbacks_from (implobj); 
+#endif
+
+
+/* - - - - - - - - - - -
+ * implobj i_objsession 
+ * - - - - - - - - - - - 
+ */
+
+/**
+ * mysv_session_control()
+ * remote server i_objsession._session_control()
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ * assuming we return a zero result to etchstub_session_control(), 
+ * etchstub_session_control() assumes the control and value objects have been   
+ * assumed by this method, so we destroy them accordingly.
+ */
+int mysv_session_control (etch_stub* thisx, etch_event* control, etch_int32* value)
+{
+    if (control)
+    {   gsv_controlval = control->value;
+        control->destroy(control);
+    }
+    if (value)
+    {   gsv_valueval = value->value;
+        value->destroy(value);
+    }
+    gsv_what = SESSION_CONTROL;
+    return 0;
+}
+
+
+/**
+ * mysv_session_notify()
+ * remote server i_objsession._session_notify()
+ * @param evt event, caller relinquishes.
+ * assuming we return a zero result to etchstub_session_notify(), 
+ * etchstub_session_notify() assumes the event object has been   
+ * assumed by this method, so we destroy it accordingly.
+ */
+int mysv_session_notify (etch_stub* thisx, etch_event* evt)
+{
+    if (evt)
+    {   gsv_eventval = evt->value;
+        evt->destroy(evt);
+    }
+    gsv_what  = SESSION_NOTIFY;
+    return 0;
+}
+
+
+/**
+ * mysv_session_query()
+ * remote server i_objsession._session_query()
+ * @param query, caller relinquishes. 
+ * assuming we return a non-null result object to etchstub_session_query(), 
+ * etchstub_session_query() assumes the query object has been assumed by 
+ * this method, so we destroy it accordingly.
+ */
+etch_int32* mysv_session_query (etch_stub* thisx, etch_query* query) 
+{
+    if (query) 
+    {   gsv_queryval = query->value;
+        etch_free(query);
+    }
+    gsv_what = SESSION_QUERY;
+    return gsv_query_result;  
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * implementing object constructor
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * mysv_howdy
+ * implementation of my_implobj.howdy().
+ */
+int mysv_howdy (my_implobj* thisx, i_delivery_service* ids, etch_who* who, etch_message* msg)
+{
+    gsv_what = HOWDY;
+    gsv_ds   = ids;
+    gsv_who  = who;
+    gsv_message = msg;
+    return 0;
+}
+
+
+/**
+ * destroy_my_implobj()
+ * destructor for our fake stub impl object
+ */
+int destroy_my_implobj(my_implobj* thisx)
+{
+    etch_free(thisx->either_base->iobjsession);
+    ETCHOBJ_DESTROY(thisx->either_base);
+    return destroy_objectex((objmask*) thisx);
+}
+
+
+/**
+ * new_my_implobj()
+ * instatiate and return an implementing object for the test stub.
+ * the only requisite of the stub's implementing object vis a vis this test,
+ * is that it implement the i_objsession interface. the stub makes this
+ * determination in etchstub_get_session_callbacks_from().
+ */
+my_implobj* new_my_implobj()
+{
+    i_objsession* ios = NULL;
+
+    /* for the test it doesn't matter whether we use obj_type of client or server,
+     * it needs to be one or the other so etchstub_get_session_callbacks_from() 
+     * will be able to extract its objession interface. in pratice the implementing
+     * object would be either a client implementation or a server implementation,
+     * however the test uses only the session interfaces so the object is androgynous.
+     */
+    my_implobj* implobj = (my_implobj*) new_object (sizeof(my_implobj), 
+        ETCHTYPEB_EXECLIENTIMPL, get_dynamic_classid_unique(&CLASSID_MY_IMPLOBJ)); 
+
+    implobj->either_base = (i_xxxx_either*) new_object (sizeof(i_xxxx_either), 
+        ETCHTYPEB_EXECLIENTBASE, get_dynamic_classid_unique(&CLASSID_MY_IMPLBASE));
+
+    /* populate as much of i_xxxx_either as we need */
+    implobj->destroy = destroy_my_implobj;
+    implobj->either_base->thisx = (objmask*) implobj;  
+    ios = new_default_objsession_interface (implobj);
+    implobj->either_base->iobjsession = ios;
+    implobj->either_base->_session_control = ios->_session_control = mysv_session_control;
+    implobj->either_base->_session_notify  = ios->_session_notify  = mysv_session_notify;
+    implobj->either_base->_session_query   = ios->_session_query   = mysv_session_query;
+ 
+    /* populate as much of xxxx_either_impl as we need */
+    implobj->iobjsession = ios;
+    implobj->_session_control = ios->_session_control; 
+    implobj->_session_notify  = ios->_session_notify; 
+    implobj->_session_query   = ios->_session_query; 
+
+    implobj->howdy = mysv_howdy; /* custom method */
+    return implobj;
+}
+
+
+/* - - - - - - - - - - -
+ * thread pool override 
+ * - - - - - - - - - - -
+ */
+
+/**
+ * thistest_proxy_run()
+ * intercept of thread pool's run() which susequently calls the real run()
+ */
+etch_thread* thistest_proxy_threadpool_run (etch_threadpool* pool, etch_threadproc threadproc, void* threaddata)
+{    
+    switch(pool->pooltype)
+    { 
+        case ETCH_THREADPOOLTYPE_FREE:
+             g_is_run_on_free_pool = TRUE;
+             return g_real_fpool_run (pool, threadproc, threaddata);
+
+        case ETCH_THREADPOOLTYPE_QUEUED:
+             g_is_run_on_queued_pool = TRUE;
+             return g_real_qpool_run (pool, threadproc, threaddata);
+    }
+
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - -
+ * stub 
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * stubhelper_howdy()
+ * stub helper (execution logic) for the mt_howdy message type. such methods    
+ * conform to typedef opaque_stubhelper and are defined with the stub, and
+ * attached to the type in the stub implementation constructor. 
+ */
+int mystub_run_howdy (void* stub, i_delivery_service* ds, i_xxxx_either* obj, etch_who* whofrom, etch_message* msg)
+{
+    int result = 0;
+    my_implobj* implobj = NULL;
+    if (NULL == obj || NULL == obj->thisx)
+    {   /* we can't use cunit macros away from the main thread, so we log errors instead */
+        etchlog(LOGSRC, ETCHLOG_ERROR, "stub helper object null pointer\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    implobj = (my_implobj*) obj->thisx;
+
+    if (implobj->class_id != CLASSID_MY_IMPLOBJ)
+    {   etchlog(LOGSRC, ETCHLOG_ERROR, "unexpected stub helper object type\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    /* execute implemented service method */
+    result = implobj->howdy (implobj, ds, whofrom, msg);   
+
+    if (0 != result)
+    {   etchlog(LOGSRC, ETCHLOG_ERROR, "service method implementation failed\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    return result;
+}
+
+
+/**
+ * new_my_stubparams()
+ * the stub carries around an etch_server_factory parameter bundle, which
+ * contains not only the server "factories" (virtual constructors, not used
+ * in these tests), but also various other parameters needed by methods which
+ * see the stub, and which a real-world stub would not have access to globally. 
+ * one such parameter is the "server", masked by i_xxxx_either, from which the 
+ * stub helper exepcts to extract the stub implementation object. we therefore
+ * must instantiate one of these objects for the purposes of this test.
+ */
+etch_server_factory* new_my_stubparams(xxxx_either_impl* implobj, etch_threadpool* qp, etch_threadpool* fp)
+{
+    g_stubparams = new_server_factory (NULL, NULL, NULL, NULL);  
+    g_stubparams->fpool = fp;
+    g_stubparams->qpool = qp;
+    // g_stubparams->in_delsvc = g_my_ds;
+    g_stubparams->in_resx = g_my_resources;    
+    g_stubparams->in_valufact = (etch_value_factory*) g_my_vf;
+    /* params->server is an i_xxxx_server, expected by the stub helper
+     * (mystub_run_howdy in this case) */    
+    g_my_iserver = etch_malloc(sizeof(i_xxxx_either), 0);
+    memset(g_my_iserver, 0, sizeof(i_xxxx_either));
+    g_my_iserver->thisx  = (objmask*) implobj; 
+    // g_stubparams->server = g_my_iserver;
+    return g_stubparams;
+}
+ 
+
+/**
+ * new_stub()
+ * etch_stub (stub base) constructor. 
+ * since we are testing only the stub base, we don't have access to the value 
+ * factory through it, and so will instead use our global value factory to access 
+ * the howdy message type and then set its stub helper to the above.
+ */
+etch_stub* new_mystub (xxxx_either_impl* implobj, unsigned char stubtype, 
+    i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp) 
+// TODO REMOVE DS FROM THIS API
+{
+    etch_stub* stubbase = NULL;
+    xxxx_either_stub* stubimpl = NULL;
+    i_xxxx_either* stubimplobj = implobj->either_base;
+
+    setup_this_stub(implobj, stubtype, qp, fp);
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    // stub base is instatiated in new_stubimpl_init()
+    // stubbase = new_stub (implobj, stubtype, g_my_ds, qp, fp);
+
+    stubimpl = new_stubimpl_init (stubimplobj, sizeof(xxxx_either_stub), 
+        stubtype, NULL, g_my_ds, qp, fp, g_stubparams);
+
+    stubbase = stubimpl->stub_base;
+    stubbase->is_implobj_owned = TRUE; /* let stubbase destroy its implobj */
+ 
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    /* fyi new_stub() has copied the objesession interface from implobj thusly:   
+     * stubbase->impl_callbacks = etchstub_get_session_callbacks_from (implobj); 
+     */
+
+    /* instantiate parameter bundle to provide stubbase helper arguments */
+    // stubbase->params = new_my_stubparams(implobj, qp, fp);   
+    // stubbase->params->stubbase = stubbase;   
+
+    /* these tests call the stubbase's session_message(), session_notify, etc. 
+     * note that the stubbase's i_sessionmessage implementations, which are
+     * etchstub_session_message, etchstub_session_notify(), etc., invoke the
+     * objsession callbacks as set per comment immediately above. 
+     * of particular note is etchstub_session_message, which gets the type
+     * from the message, gets the stubbase "helper" (run procedure) from the message
+     * type, checks the type's async mode, and runs the proc inline or on a thread
+     * accordingly.
+     */
+    etchtype_set_type_stubhelper (g_mt_howdy, mystub_run_howdy);
+    stubbase->session_message = myds_session_message;
+
+    return stubbase;
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * unit tests
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_setup()
+ */
+void test_setup(void)
+{
+    setup_this_test();
+
+    do
+    {   
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_message_1()
+ * test a stub runner run on main thread 
+ */
+void test_session_message_1(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_NONE);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+
+        /* todo in some places we pass session_message a delivery service, 
+         * but here we pass the stub. wtf? find the discrepancy and fix it. 
+         * ds can get the stub via its ism.thisx. stub can get ds via stub.params.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, FALSE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, FALSE);    
+       
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_message_2()
+ * test a stub runner run on queued thread pool 
+ */
+void test_session_message_2(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_QUEUED);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+
+        /* if we don't implement a queued pool, a free pool was substituted */
+        #if ETCH_HAS_QUEUED_THREADPOOL
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, TRUE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, FALSE);  
+        #else
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, TRUE);  
+        #endif
+       
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_message_3()
+ * test a stub runner run on free thread pool 
+ */
+void test_session_message_3(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_FREE);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, FALSE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, TRUE);  
+       
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_message_4()
+ * test sending a message whose type has no stub runner
+ */
+void test_session_message_4(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, was_msg_handled = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        newmsg = new_message (g_mt_nogood, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+
+        was_msg_handled = (0 == result);
+        CU_ASSERT_EQUAL(was_msg_handled, FALSE);   
+        CU_ASSERT_EQUAL(gsv_what, 0); 
+        CU_ASSERT_PTR_NULL(gsv_ds);  
+        CU_ASSERT_PTR_NULL(gsv_who); 
+        CU_ASSERT_PTR_NULL(gsv_message); 
+
+        /* fyi messages are not relinquished on failure 
+         * since caller may want to reroute the message on failure */
+        if (!was_msg_handled)
+            newmsg->destroy(newmsg);
+       
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_query()
+ */
+void test_session_query(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISQUERYVAL = 12345;
+        objmask* resultobj = NULL;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        resultobj = stub->session_query (stub, new_etch_query(0, THISQUERYVAL));
+
+        CU_ASSERT_PTR_NOT_NULL(resultobj); 
+        CU_ASSERT_PTR_EQUAL(resultobj, gsv_query_result); 
+        CU_ASSERT_EQUAL(SESSION_QUERY, gsv_what);
+        CU_ASSERT_EQUAL(THISQUERYVAL, gsv_queryval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_control()
+ */
+void test_session_control(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISCONTROLVAL = 12345, THISVALUEVAL = 54321;
+        int result = 0;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        result = stub->session_control (stub, new_etch_control(0, THISCONTROLVAL), new_int32(THISVALUEVAL));
+
+        CU_ASSERT_EQUAL(result,0); 
+        CU_ASSERT_EQUAL(SESSION_CONTROL, gsv_what);
+        CU_ASSERT_EQUAL(THISCONTROLVAL, gsv_controlval);
+        CU_ASSERT_EQUAL(THISVALUEVAL, gsv_valueval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+/**
+ * test_session_notify()
+ */
+void test_session_notify(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISNOTIFYVAL = 12345;
+        int result = 0;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        result = stub->session_notify (stub, new_etch_event (0, THISNOTIFYVAL));
+
+        CU_ASSERT_EQUAL(result,0); 
+        CU_ASSERT_EQUAL(SESSION_NOTIFY, gsv_what);
+        CU_ASSERT_EQUAL(THISNOTIFYVAL, gsv_eventval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   /* start fresh for next test */   
+}
+
+
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    CU_pSuite ps = NULL;
+    g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+    if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+    CU_set_output_filename("../test_stub");
+    ps = CU_add_suite("stub base test suite", init_suite, clean_suite);
+    etch_watch_id = 0; 
+
+    // THESE TESTS ARE BROKEN
+    // TODO go back to java test and reimplement these tests
+    //CU_add_test(ps, "test test setup and teardown", test_setup);
+    //CU_add_test(ps, "test send message main thread", test_session_message_1);
+    //CU_add_test(ps, "test send message queued pool", test_session_message_2);
+    //CU_add_test(ps, "test send message freepool", test_session_message_3);
+    //CU_add_test(ps, "test send message no good", test_session_message_4);   
+    //CU_add_test(ps, "test session query", test_session_query); 
+    //CU_add_test(ps, "test session control", test_session_control); 
+    //CU_add_test(ps, "test session notify", test_session_notify); 
+    
+    if (g_is_automated_test)    
+        CU_automated_run_tests();    
+    else
+    {   CU_basic_set_mode(CU_BRM_VERBOSE);
+        CU_basic_run_tests();
+    }
+
+    if (!g_is_automated_test) { printf("any key ..."); while(!_getch()); printf("\n"); }     
+    CU_cleanup_registry();
+    return CU_get_error();
+}
\ No newline at end of file