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 [35/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/transport/test_tcp_connection.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcp_connection.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcp_connection.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcp_connection.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,975 @@
+/* $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_tcp_connection.c
+ */
+
+#include "etch_apr.h" /* some apr must be included first */
+#include "etch_connection.h"  /* must be included second */
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_connection.h"
+#include "etch_tcpserver.h"
+#include "etch_global.h"
+#include "etch_encoding.h"
+#include "etchflexbuf.h"
+#include "etchthread.h"
+#include "etchlog.h"
+int this_setup();
+int this_teardown();
+
+int init_suite(void)
+{
+    if  (0 == etch_runtime_init_all(0)) 
+         return this_setup();
+    else return -1;
+}
+
+int clean_suite(void)
+{
+    this_teardown();
+    return etch_runtime_exit(0);
+}
+
+#define IS_DEBUG_CONSOLE TRUE
+int g_is_automated_test, g_bytes_allocated;
+
+
+#define RCVBUFLEN 256
+#define TEST_PORT 7302
+#define TEST_IP   L"127.0.0.1"
+etch_url* g_test_url;
+char* g_ip8bit;
+
+int on_data_server_test_write_to_server    (etch_tcp_connection*, const int, int, etch_flexbuffer*);
+int on_data_server_test_write_with_readback(etch_connection*, const int, int, etch_flexbuffer*);
+int on_data_client_test_write_with_readback(etch_tcp_connection*, const int, int, char*);
+
+char *g_senddata1="By the rude bridge that arched the flood, their flag from April's breeze unfurled";
+char *g_senddata2="And therefore I have sailed the seas and come, to the holy city of Byzantium.";
+int   g_buflen1, g_buflen2;
+
+
+int this_setup()
+{
+    g_buflen1 = (int)strlen(g_senddata1); g_buflen2 = (int)strlen(g_senddata2);
+    return 0;
+}
+
+int this_teardown()
+{    
+    return 0;
+}
+
+etch_url* get_test_url() /* build a URL string for the test */
+{   
+    wchar_t buf[256]; swprintf(buf, sizeof(buf), L"%s:%d", TEST_IP, TEST_PORT);
+    return new_url(buf);
+} 
+
+/**
+ * test_unicode_conversion()
+ * test the etch unicode to 8 bit conversion
+ * this test does not necessarily belong in this suite, it is here because
+ * we use the conversion in the tcp connection classes and in these tests.
+ */
+void test_unicode_conversion(void)
+{
+    int result = 0;
+    wchar_t *widestring = L"it works!";
+    char *narrowstring  =  "it works!", *out_8bit = NULL;
+
+    /* unicode to 8 bit ansi */
+    result = etch_unicode_to_ansi(&out_8bit, widestring);
+    CU_ASSERT_EQUAL(result,0); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_8bit);
+    
+    result = strcmp(out_8bit, narrowstring);
+    CU_ASSERT_EQUAL(result,0); 
+
+    /* we own returned buffer */
+    etch_free(out_8bit); out_8bit = NULL;
+ 
+    /* unicode to utf-8 */
+    result = etch_unicode_to_utf8(&out_8bit, widestring);
+    CU_ASSERT_EQUAL(result,0); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_8bit); 
+
+    result = strcmp(out_8bit, narrowstring);
+    CU_ASSERT_EQUAL(result,0);   
+    
+    etch_free(out_8bit); out_8bit = NULL;
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_unicode_conversion2()
+ * test the etch 8 bit to unicode conversion
+ * this test does not necessarily belong in this suite, it is here because
+ * we use the conversion in the tcp connection classes and in these tests.
+ */
+void test_unicode_conversion2(void)
+{
+    int result = 0;
+    wchar_t *widestring = L"it works!", *out_unicode = NULL;
+    char *narrowstring  =  "it works!";
+
+    /* 8 bit ansi to unicode */
+    result = etch_ansi_to_unicode(&out_unicode, narrowstring);
+    CU_ASSERT_EQUAL(result,0); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_unicode);
+    
+    result = wcscmp(out_unicode, widestring);
+    CU_ASSERT_EQUAL(result,0); 
+
+    /* we own returned buffer */
+    etch_free(out_unicode); out_unicode = NULL;
+ 
+    /* utf-8 to unicode */
+    result = etch_ansi_to_unicode(&out_unicode, narrowstring);
+    CU_ASSERT_EQUAL(result,0); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_unicode); 
+
+    result = wcscmp(out_unicode, widestring);
+    CU_ASSERT_EQUAL(result,0);   
+    
+    etch_free(out_unicode); out_unicode = NULL;
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * setup_a_test()
+ * set up a tcp server test by creating and returning an 
+ * initialized tcp server object.
+ */
+etch_tcp_server* setup_a_test()
+{
+    etch_tcp_server* tcp_server = 0;
+    etch_tcp_connection* cxl = 0;  
+    etch_threadpool* pool = 0; 
+    etch_connection* cx = 0;
+
+    #if IS_DEBUG_CONSOLE 
+    wprintf(L"\n");          
+    #endif   
+
+    /* create objects */ 
+
+    g_test_url = get_test_url();  
+    CU_ASSERT_STRING_EQUAL_FATAL(g_test_url->host, TEST_IP);
+    CU_ASSERT_EQUAL_FATAL(g_test_url->port, TEST_PORT);
+    etch_unicode_to_ansi(&g_ip8bit, TEST_IP);
+
+    pool = new_threadpool (ETCH_THREADPOOLTYPE_FREE, 0); 
+
+    tcp_server = new_tcp_server(g_test_url, pool, pool, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL(tcp_server);
+    tcp_server->is_threadpool_owned = TRUE;  /* server now owns pool */
+
+    CU_ASSERT_EQUAL (tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED);
+    CU_ASSERT_NOT_EQUAL (tcp_server->listener_id, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->cxlisten);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->on_event);
+    
+    cxl = tcp_server->cxlisten; /* listen socket connection object */
+    cx  = &cxl->cx; 
+    CU_ASSERT_PTR_NULL_FATAL (cx->socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->mutex);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->listener);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_data);
+    CU_ASSERT_EQUAL_FATAL (cx->is_ownpool, TRUE);
+    CU_ASSERT_EQUAL_FATAL (cx->is_started, FALSE);
+
+    return tcp_server;
+}
+
+
+/**
+ * teardown_a_test()
+ * tear down a tcp server test by destroying the specified tcp server 
+ * object plus the various objects created to set it up.
+ */
+void teardown_a_test(etch_tcp_server* listener)
+{
+    etch_free(g_ip8bit);  
+    listener->destroy(listener);    
+    g_test_url->destroy(g_test_url); g_test_url = NULL;
+}
+
+
+/**
+ * test_server_create_destroy()
+ * test that we can create a tcp server with all expected pieces present,
+ * and subsequently destroy it with all memory accounted for. also tests
+ * creation of a connection object (the server's listener connection).
+ * tests only construction and destruction, no other functionality. 
+ * assuming we run this test early and it passes, we can safely omit 
+ * a lot of asserts in subsequent tests.
+ */
+void test_server_create_destroy(void)
+{
+    etch_threadpool* thread_manager = 0;
+    etch_tcp_server* tcp_server = 0;
+    etch_tcp_connection* cxl = 0;    
+     
+    etch_connection* cx = 0;
+    etch_url* url = 0;
+    #if IS_DEBUG_CONSOLE 
+    wprintf(L"\n");          
+    #endif   
+
+    /* start - create objects */ 
+    url = get_test_url(); /* we own it */
+    CU_ASSERT_STRING_EQUAL_FATAL(url->host, TEST_IP);
+    CU_ASSERT_EQUAL_FATAL(url->port, TEST_PORT);
+
+    tcp_server = new_tcp_server(url, NULL, NULL, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL(tcp_server);
+
+    CU_ASSERT_EQUAL (tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED);
+    CU_ASSERT_EQUAL (tcp_server->listener_id, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->cxlisten);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->on_event);
+    
+    cxl = tcp_server->cxlisten; /* listen socket connection object */
+    cx  = &cxl->cx; 
+    CU_ASSERT_PTR_NULL_FATAL (cx->socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->mutex);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->listener);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_data);
+    CU_ASSERT_EQUAL_FATAL (cx->is_ownpool, TRUE);
+    CU_ASSERT_EQUAL_FATAL (cx->is_started, FALSE);
+
+    /* done - destroy objects */ 
+    tcp_server->destroy(tcp_server);    
+    url->destroy(url);
+    //thread_manager->destroy(thread_manager);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_setup_a_test()
+ * test that we can do the same as test_server_create_destroy(), but using
+ * setup_a_test() and teardown_a_test to create and destroy objects.
+ */
+void test_setup_a_test(void)
+{
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    teardown_a_test(tcp_server);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_server_open_close()
+ * test that we can create, open, close, and destroy a tcp server 
+ * with all memory accounted for. when server is open, its listen socket is
+ * listening on the designated port. when closed, it is not listening.
+ */
+void test_server_open_close(void)
+{
+    int result;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL(result, 0);  /* state stopped means not closed but not started */
+    CU_ASSERT_EQUAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    if (result == 0)
+    {   result = etch_tcpsvr_close(tcp_server);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED); 
+    }
+
+    teardown_a_test(tcp_server);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_server_start_stop()
+ * test that we can create, open, start, stop, close, and destroy a tcp server 
+ * with all memory accounted for. when server is started, it is accepting
+ * connections from clients.
+ */
+void test_server_start_stop(void)
+{
+    int result;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->threadpool); 
+    CU_ASSERT_EQUAL_FATAL (tcp_server->is_started, TRUE); 
+    CU_ASSERT_EQUAL_FATAL (tcp_server->state, ETCH_TCPSERVER_STATE_STARTED); 
+
+    etch_sleep(1000);
+
+    result = etch_tcpsvr_stop(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0);    
+
+    teardown_a_test(tcp_server);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_server_control_start_stop()
+ */
+void test_server_control_start_stop(void)
+{
+    int result = 0;
+    etch_event *startevent = NULL, *stopevent = NULL;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    startevent = new_etch_event(CLASSID_CONTROL_START, 0); /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, startevent, NULL);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, TRUE); 
+
+    stopevent = new_etch_event(CLASSID_CONTROL_STOP, 0);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, stopevent, NULL);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, FALSE); 
+  
+    teardown_a_test(tcp_server);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_server_control_waitup_waitdown()
+ */
+void test_server_control_waitup_waitdown(void)    
+{
+    int result = 0;
+    etch_event *waitupevent = NULL, *waitdownevent = NULL;
+    etch_int32 *waituptime  = NULL, *waitdowntime  = NULL;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    waitupevent = new_etch_event(CLASSID_CONTROL_START_WAITUP, 0); /* we relinquish this */
+    waituptime  = new_int32(5000);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, waitupevent, waituptime);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, TRUE); 
+
+    waitdownevent = new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, 0);  /* we relinquish this */
+    waitdowntime  = new_int32(5000);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, waitdownevent, waitdowntime);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, FALSE); 
+
+    teardown_a_test(tcp_server);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_connect_to_server()
+ * test that we can open and close a client connection to a tcp server.
+ */
+void test_connect_to_server(void)
+{
+    int result;
+    etch_tcp_connection* cxclient = 0;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    etch_sleep(1000);  
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+
+    result = etch_tcpconx_open(cxclient, FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_STRING_EQUAL_FATAL(cxclient->cx.hostname, g_ip8bit);
+    CU_ASSERT_EQUAL_FATAL(cxclient->cx.port, TEST_PORT);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.on_data);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.aprpool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.mutex);
+  
+    etch_sleep(500);
+
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_stop(tcp_server);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    if (cxclient) cxclient->destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+
+/**
+ * test_multiple_connect_to_server()
+ * test that we can open and close two concurrent connections to a tcp server.
+ */
+void test_multiple_connect_to_server(void)
+{
+    int result;
+    etch_tcp_connection *cxclient_a = 0, *cxclient_b = 0;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);  
+
+    cxclient_a = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_b = new_tcp_connection(g_test_url, NULL, NULL);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_a);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b);
+
+    result = etch_tcpconx_open(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpconx_open(cxclient_b, FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_STRING_EQUAL_FATAL(cxclient_b->cx.hostname, g_ip8bit);
+    CU_ASSERT_EQUAL_FATAL(cxclient_b->cx.port, TEST_PORT);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.on_data);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.aprpool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.mutex);
+
+    etchlog("TEST", ETCHLOG_DEBUG, "client a ID is %d\n", cxclient_a->cx.conxid); 
+    etchlog("TEST", ETCHLOG_DEBUG, "client b ID is %d\n", cxclient_b->cx.conxid); 
+    etch_sleep(500);
+
+    result = etch_tcpconx_close(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpconx_close(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_stop(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    if (cxclient_a) cxclient_a->destroy(cxclient_a);
+    if (cxclient_b) cxclient_b->destroy(cxclient_b);
+
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/*
+ * on_data_server_test_write_to_server()
+ * server on_data overide for the test_write_to_server() test 
+ */
+int on_data_server_test_write_to_server(etch_tcp_connection* c, const int unused, int len, etch_flexbuffer* fbuf)
+{
+    char* datacopy = 0;
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, "conxn %d on_data server test overide got %d bytes ...\n", 
+        c->cx.conxid, len);    
+    datacopy = etch_malloc(len+2,0); 
+    memcpy(datacopy, fbuf->buf, len);
+    datacopy[len] = '\n'; datacopy[len+1] = '\0';
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, datacopy); 
+    return etch_free(datacopy);
+}
+
+
+/**
+ * test_write_to_server()
+ * test that we can send a message to a tcp server.
+ */
+void test_write_to_server(void)
+{
+    int result = 0, arc = 0;
+    etch_tcp_connection* cxclient = 0;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    /* this test overrides server's accepted connection data handler */
+    tcp_server->on_data = on_data_server_test_write_to_server;  
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    etch_sleep(500); /* not needed, used for watching console */ 
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+
+    result = etch_tcpconx_open(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* send data to server */
+    etch_tcpclient_send(cxclient, g_senddata1, g_buflen1, &arc);  
+
+    /* if omit this sleep, server receives both sends as one,  
+     * either way is is fine */
+     etch_sleep(200); 
+
+    /* send more data to server */
+    etch_tcpclient_send(cxclient, g_senddata2, g_buflen2, &arc);  
+
+    etch_sleep(500); /* not needed, used for watching console */
+
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* test that we can omit an explicit server stop */
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    if (cxclient) cxclient->destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/*
+ * on_data_server_test_write_with_readback()
+ * receive data handler for server side of test_write_with_readback
+ * this is not executed on the main thread, so no CU_ASSERTs can appear here.
+ * logs data received at the tcp server and sends it back to client
+ */
+int on_data_server_test_write_with_readback(etch_connection* cx, const int unused, int length, etch_flexbuffer* fbuf)
+{
+    char* datacopy = 0; int arc = 0;
+    etch_tcp_server* tcps = (etch_tcp_server*) cx->listener;
+    etch_tcp_connection* tcpx = tcps? tcps->cxlisten: NULL;
+    assert(is_etch_tcpserver(tcps));
+    assert(is_etch_tcpconnection(tcpx));
+ 
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, 
+        "connxn %d TEST SERVER ONDATA GOT %d bytes ...\n", cx->conxid, length);
+
+    datacopy = etch_malloc(length+2,0); memcpy(datacopy, fbuf->buf, length);
+    datacopy[length] = '\n'; datacopy[length+1] = '\0';
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, datacopy); 
+
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, 
+        "conxn %d TEST SERVER ONDATA RESENDING to client \n", tcpx->cx.conxid);
+    etch_tcpclient_send (tcpx, fbuf->buf, length, &arc); /* return to sender */
+
+    return etch_free(datacopy);
+}
+
+
+/*
+ * on_data_client_test_write_with_readback()
+ * receive data handler for client side of test_write_with_readback 
+ * just logs the data received back from tcp server 
+ */
+int on_data_client_test_write_with_readback (etch_tcp_connection* c, const int unused, int length, char* data)
+{
+    char* datacopy = 0;
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, 
+        "connxn %d TEST CLIENT ONDATA GOT %d bytes ...\n", c->cx.conxid, length);
+    datacopy = etch_malloc(length+2,0); memcpy(datacopy, data, length);
+    datacopy[length] = '\n'; datacopy[length+1] = '\0';
+    etchlog(ETCHCONX, ETCHLOG_DEBUG, datacopy); 
+    return etch_free(datacopy);
+}
+
+
+/**
+ * test_write_with_readback()
+ * test that we can send data to server and that server can send it back to us
+ */
+void test_write_with_readback(void)
+{
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection *cxclient = 0;
+    etch_tcp_server *tcp_server = 0;
+    etch_tcp_client *tcp_client = 0;
+
+    /* 
+     * create and start a tcp server  
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "CREATING SERVER\n");
+    tcp_server = setup_a_test(); 
+    /* override server's accepted socket data handler to be our test handler */
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+
+    etchlog("TEST", ETCHLOG_DEBUG, "STARTING SERVER\n");
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* 
+     * open a client connection and listener 
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "CREATING CLIENT CONNECTION\n");
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient->cx.on_data = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+    etchlog("TEST", ETCHLOG_DEBUG, "client connection ID is %d\n", cxclient->cx.conxid); 
+
+   /* opening this client connection results in an accepted connection on our server.
+    * that accepted connection will recognize and use our test data handler, since we
+    * overrode that handler above. */
+    etchlog("TEST", ETCHLOG_DEBUG, "OPENING CLIENT CONNECTION\n");
+    result = etch_tcpconx_open (cxclient, FALSE);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* start a client side listener for the client socket - this is normally done
+     * via a start/waitup mechanism, however for the unit test we do so explicitly here.
+     * note that the tcp_client class is normally not visible, we expose it for the test. */
+    etchlog("TEST", ETCHLOG_DEBUG, "STARTING CLIENT LISTENER THREAD\n");
+    result = etch_tcpclient_start_listener (cxclient);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    tcp_client = cxclient->rcvlxr; /* check the mutual tcp connection references */
+    CU_ASSERT_PTR_EQUAL_FATAL(cxclient, tcp_client->cxlisten);
+
+    /* 
+     * send data to server and receive data back from server
+     * note that both server and client data handlers are overridden above
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "SENDING DATA TO SERVER\n");
+    etch_tcpclient_send(cxclient, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive(cxclient, rcvbuf, RCVBUFLEN, &rcvrc);     
+
+    CU_ASSERT_EQUAL(datalen, g_buflen1); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata1, datalen));
+
+    /* 
+     * send more data to server and receive data back from server
+     */
+    //etchlog("TEST", ETCHLOG_DEBUG, "SENDING MORE DATA TO SERVER\n");
+    //etch_tcpclient_send(cxclient, g_senddata2, g_buflen2, &sndrc); 
+    //datalen = etch_tcpclient_receive(cxclient, rcvbuf, RCVBUFLEN, &rcvrc);  
+
+    //CU_ASSERT_EQUAL(datalen, g_buflen2); /* verify sent == received */
+    //CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata2, datalen));   
+
+    /* stop the client side listener thread - this is normally done via a
+     * stop/waitdown mechanism, however for the unit test we do so explicitly here */
+    etchlog("TEST", ETCHLOG_DEBUG, "STOPPING CLIENT LISTENER THREAD\n");
+    result = etch_tcpclient_stop_listener (cxclient);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);      
+   
+    /* 
+     * close client connection
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "CLOSING CLIENT CONNECTION\n");
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* 
+     * shut down tcp server  
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "STOPPING SERVER\n");
+    result = etch_tcpsvr_stop(tcp_server); /* could omit this */
+    CU_ASSERT_EQUAL(result, 0);  
+   
+    etchlog("TEST", ETCHLOG_DEBUG, "CLOSING SERVER\n");
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* 
+     * free memory
+     */
+    if (cxclient) cxclient->destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_multiple_client_write_with_readback()
+ * test that two clients can send data to server and receive it back.
+ */
+void test_multiple_client_write_with_readback(void)
+{
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection *cxclient_a = 0, *cxclient_b = 0;
+    etch_tcp_server* tcp_server = 0;
+
+    /* 
+     * create and start a tcp server  
+     */
+    tcp_server = setup_a_test(); 
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);
+
+    /* 
+     * open multiple client connections   
+     */
+    cxclient_a = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_a->cx.on_data = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_a);
+    etchlog("TEST", ETCHLOG_DEBUG, "client a id is %d\n", cxclient_a->cx.conxid); 
+
+    cxclient_b = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_b->cx.on_data /* override data handler */
+        = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b);
+    etchlog("TEST", ETCHLOG_DEBUG, "client b id is %d\n", cxclient_b->cx.conxid); 
+
+    result = etch_tcpconx_open(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    result = etch_tcpconx_open(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);
+
+    /* 
+     * client a send data to server and receive data back from server
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "client a sending data\n", cxclient_b->cx.conxid); 
+    etch_tcpclient_send(cxclient_a, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive(cxclient_a, rcvbuf, RCVBUFLEN, &rcvrc); 
+
+    CU_ASSERT_EQUAL(datalen, g_buflen1); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata1, datalen));
+
+    /* 
+     * client b send data to server and receive data back from server
+     */
+    etchlog("TEST", ETCHLOG_DEBUG, "client b sending data\n", cxclient_b->cx.conxid); 
+    etch_tcpclient_send(cxclient_b, g_senddata2, g_buflen2, &sndrc); 
+    datalen = etch_tcpclient_receive(cxclient_b, rcvbuf, RCVBUFLEN, &rcvrc);  
+
+    CU_ASSERT_EQUAL(datalen, g_buflen2); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata2, datalen)); 
+    etch_sleep(500);    
+   
+    /* 
+     * close client connections
+     */
+    result = etch_tcpconx_close(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL(result, 0);
+    result = etch_tcpconx_close(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* 
+     * shut down tcp server  
+     */
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* 
+     * free memory
+     */
+    if (cxclient_a) cxclient_a->destroy(cxclient_a);
+    if (cxclient_b) cxclient_b->destroy(cxclient_b);
+
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * test_receive_with_timeout()
+ * test that we can time out a receive operation
+ */
+void test_receive_with_timeout(void)
+{  
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection* cxclient = 0;
+    etch_tcp_server* tcp_server = 0;
+
+    tcp_server = setup_a_test(); 
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+    result = etch_tcpsvr_open (tcp_server, 0);
+    result = etch_tcpsvr_start(tcp_server);
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    result = etch_tcpconx_open(cxclient, FALSE);
+
+    /* do one send and two receives, the 2nd with 2-second timeout */
+    etch_tcpclient_send(cxclient, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive (cxclient, rcvbuf, RCVBUFLEN, &rcvrc);  
+    datalen = etch_tcpclient_receivex(cxclient, rcvbuf, RCVBUFLEN, 2000, &rcvrc);  
+    CU_ASSERT_EQUAL(IS_ETCH_SOCKET_TIMEOUT(rcvrc), TRUE);  
+   
+    result = etch_tcpconx_close(cxclient, FALSE);
+    result = etch_tcpsvr_close(tcp_server);
+    if (cxclient) cxclient->destroy(cxclient);
+    teardown_a_test(tcp_server);
+ 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */    
+}
+
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    char c=0;
+    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_tcpconn");
+    ps = CU_add_suite("suite_tcpconn", init_suite, clean_suite);
+    etch_watch_id = 0; 
+
+    CU_add_test(ps, "test unicode conversion 2", test_unicode_conversion2);
+    CU_add_test(ps, "test unicode conversion", test_unicode_conversion);
+    CU_add_test(ps, "test create and destroy tcp server", test_server_create_destroy);
+    CU_add_test(ps, "test test setup and teardown", test_setup_a_test);
+    CU_add_test(ps, "test tcp server open/close", test_server_open_close);
+    CU_add_test(ps, "test tcp server start/stop", test_server_start_stop);
+
+    CU_add_test(ps, "test server control start/stop",   test_server_control_start_stop);
+    CU_add_test(ps, "test server control wait up/down", test_server_control_waitup_waitdown);
+
+    CU_add_test(ps, "test connect to server", test_connect_to_server);
+    CU_add_test(ps, "test multiple connect to server", test_multiple_connect_to_server);
+    CU_add_test(ps, "test write to server", test_write_to_server);
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * these last three tests used to work but are now broken.
+     * all tests that return data from server to client no longer work.
+     * the re-send of data back to client finds "socket not connected" .
+     * the production mailbox stuff works, so not sure what the problem is 
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+    // CU_add_test(ps, "test write with readback", test_write_with_readback);   
+    // CU_add_test(ps, "test multiple client write/read", test_multiple_client_write_with_readback);  
+    // CU_add_test(ps, "test receive with timeout", test_receive_with_timeout);  
+
+    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(!c) c = _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/transport/test_tcpconn.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcpconn.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcpconn.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_tcpconn.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,520 @@
+/**
+ * test_tcpconn.c
+ * test TCP connection
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etchmon.h"  /* must be included second */
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_global.h"
+#include "etchconn.h"
+#include "etchthread.h"
+#include "etchlog.h"
+
+int apr_setup(void);
+int apr_teardown(void);
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+int init_suite(void)
+{
+    apr_setup();
+    return etch_runtime_init();
+}
+
+int clean_suite(void)
+{
+    apr_teardown();
+    return etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+    int result = 0;
+    apr_status_t aprresult = apr_initialize();
+    if (aprresult == APR_SUCCESS)
+        aprresult = apr_pool_create(&g_apr_mempool, NULL);
+    if (aprresult == APR_SUCCESS)
+        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;
+}
+
+static char *testval  = "test";
+static char *VAL_UP   = "UP";
+static char *VAL_DOWN = "DOWN";
+
+void setAndWait(apr_thread_start_t setfunc, apr_thread_start_t waitfunc);
+
+
+
+void testCreateAndDestroy(void)
+{
+    etchmon *mon_ptr;
+    const size_t vlen = (strlen(testval)+1) * sizeof(char);
+    etch_apr_mempool = g_apr_mempool;
+    
+    mon_ptr = etchmon_create("testCreateAndDestroy", testval, vlen, g_apr_mempool);
+    CU_ASSERT_TRUE(mon_ptr != NULL);
+    
+    etchmon_destroy(mon_ptr);
+
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+void testSet(void)
+{
+    etchmon *mon_ptr;
+    const size_t vlen = (strlen(testval)+1) * sizeof(char);
+    etch_apr_mempool = g_apr_mempool;
+
+    mon_ptr = etchmon_create("testSet", testval, vlen, g_apr_mempool);
+    CU_ASSERT_TRUE(mon_ptr != NULL);    
+    
+    etchmon_set(mon_ptr, testval, (strlen(testval)+1)*sizeof(char));
+    CU_ASSERT_STRING_EQUAL(mon_ptr->val.value_ptr_to,testval);
+
+    etchmon_destroy(mon_ptr);
+
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+void testWaitTimeout(void)
+{
+    etchmon *mon_ptr;
+    int rc;
+    const size_t vlen = (strlen(testval)+1) * sizeof(char);
+    etch_apr_mempool = g_apr_mempool;
+
+    mon_ptr = etchmon_create("testWaitTimeout", testval, vlen, g_apr_mempool);
+    CU_ASSERT_TRUE(mon_ptr != NULL);
+    
+    rc = etchmon_wait_until_set(mon_ptr, 10000);
+    CU_ASSERT( rc == ETCHMON_STATUS_TIMEOUT);
+
+    etchmon_destroy(mon_ptr);
+
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+static void* APR_THREAD_FUNC threadSetFunc(apr_thread_t *thread_ptr, void *p)
+{   
+    int s;
+    apr_status_t r;
+    const size_t vlen = (strlen(testval)+1) * sizeof(char);
+    etchmon *mon_ptr = (etchmon *) p;
+    s = etchmon_set(mon_ptr, testval, vlen);
+    CU_ASSERT(s == ETCHMON_STATUS_SUCCESS);
+    r = apr_thread_exit(thread_ptr, APR_SUCCESS);
+
+    return NULL;
+}
+
+
+static void* APR_THREAD_FUNC threadWaitFunc(apr_thread_t *thread_ptr, void *p)
+{
+    int w;
+    apr_status_t r;
+    etchmon *mon_ptr = (etchmon *) p;
+    w = etchmon_wait_until_set(mon_ptr, 0);
+    CU_ASSERT(w == ETCHMON_STATUS_SUCCESS);
+    CU_ASSERT_STRING_EQUAL(mon_ptr->val.value_ptr_to, testval);
+    r = apr_thread_exit(thread_ptr, APR_SUCCESS);
+
+    return NULL;
+}
+
+
+static void* APR_THREAD_FUNC threadMultiSetFunc(apr_thread_t *thread_ptr, void *p)
+{   
+    int s;
+    apr_status_t r;
+    etchmon *mon_ptr = (etchmon *) p;
+    s = etchmon_set(mon_ptr, testval, (strlen(testval)+1)*sizeof(char));
+    /* sleep for a bit */
+    etch_sleep(5);
+    s = etchmon_set(mon_ptr, VAL_UP, (strlen(VAL_UP)+1)*sizeof(char));
+    etch_sleep(5);
+    s = etchmon_set(mon_ptr, VAL_UP, (strlen(VAL_DOWN)+1)*sizeof(char));
+    CU_ASSERT(s == ETCHMON_STATUS_SUCCESS);
+    r = apr_thread_exit(thread_ptr, APR_SUCCESS);
+
+    return NULL;
+}
+
+
+static void* APR_THREAD_FUNC threadWaitTillEqualFunc(apr_thread_t *thread_ptr, void *p)
+{
+    int w;
+    apr_status_t r;
+    etchmon *mon_ptr = (etchmon *) p;
+    w = etchmon_wait_until_equal(mon_ptr, VAL_UP, (strlen(VAL_UP)+1)*sizeof(char), 0);
+    CU_ASSERT(w == ETCHMON_STATUS_SUCCESS);
+    w = etchmon_wait_until_equal(mon_ptr, VAL_UP, (strlen(VAL_DOWN)+1)*sizeof(char), 0);
+    r = apr_thread_exit(thread_ptr, APR_SUCCESS);
+
+    return NULL;
+}
+
+
+/* create two threads to test synchronization */
+void testSetAndWait(void)
+{   
+    etch_apr_mempool = g_apr_mempool;
+
+    setAndWait(threadSetFunc, threadWaitFunc);
+
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+void testSetAndWaitUntilEqual(void)
+{
+    etch_apr_mempool = g_apr_mempool;
+
+    setAndWait(threadMultiSetFunc, threadWaitTillEqualFunc);
+
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+void setAndWait(apr_thread_start_t setfunc, apr_thread_start_t waitfunc)
+{
+    apr_status_t r;
+    apr_status_t rt;
+    apr_threadattr_t    *attr_ptr;
+    apr_thread_t        *set_thread_ptr;
+    apr_thread_t        *wait_thread_ptr;
+    etchmon *mon_ptr;
+    const size_t vlen = (strlen(testval)+1) * sizeof(char);
+    
+    mon_ptr = etchmon_create("testSetAndWait", testval, vlen, g_apr_mempool);
+    CU_ASSERT_TRUE(mon_ptr != NULL);
+
+    r = apr_threadattr_create(&attr_ptr, g_apr_mempool);
+    CU_ASSERT_TRUE(r == APR_SUCCESS );
+
+    r = apr_thread_create(&set_thread_ptr, attr_ptr, setfunc, (void *)mon_ptr, g_apr_mempool);
+    CU_ASSERT_TRUE(r == APR_SUCCESS );
+
+    r = apr_threadattr_create(&attr_ptr, g_apr_mempool);
+    CU_ASSERT_TRUE(r == APR_SUCCESS );  
+
+    r = apr_thread_create(&wait_thread_ptr, attr_ptr, waitfunc, (void *)mon_ptr, g_apr_mempool);
+    CU_ASSERT_TRUE(r == APR_SUCCESS );
+
+    r = apr_thread_join(&rt, set_thread_ptr);
+    CU_ASSERT(r == APR_SUCCESS);
+
+    r = apr_thread_join(&rt, wait_thread_ptr);
+    CU_ASSERT(r == APR_SUCCESS);
+
+    etchmon_destroy(mon_ptr);
+}
+
+
+
+/* ============================================================================
+ * START TCP TESTS
+ * ============================================================================
+ */
+
+etch_tcpconn     *tcpconn;
+etch_tcpconn     *tcpconn2;
+etch_tcplistener *listener;
+#define TEST_PORT 7302
+#define TEST_IP  "127.0.0.1"
+#define NUM_TEST_CONNECTIONS 10
+etch_tcpconn *accepted_connections[NUM_TEST_CONNECTIONS];
+
+
+/**
+ * received_data_handler()
+ * callback to receive data from TCP stack
+ */
+void received_data_handler(void *data, size_t len)
+{
+    etchlog("etchconntest", ETCHLOG_DEBUG, "got data '%s'\n", (const char*)data);
+}
+
+
+/**
+ * got_accepted()
+ * callback to receive notification of accepted connection
+ */
+int got_accepted(apr_socket_t *aprsocket)
+{
+    int result = 0, i = 0;
+
+    etch_tcpconn *accepted_conx = etchconn_create_tcp_with_socket(aprsocket);
+
+    if (accepted_conx != NULL)
+    {
+        /* set the data handler callback */
+        accepted_conx->conn.on_data = received_data_handler; 
+
+        result = etchconn_start((etchconn*) accepted_conx);
+        
+        /* save the pointer for later releasing */
+
+        while(i < NUM_TEST_CONNECTIONS && accepted_connections[i] != NULL)
+              ++i;
+
+        if (i < NUM_TEST_CONNECTIONS)
+            accepted_connections[i] = accepted_conx;
+    }
+
+    return result;
+}
+
+
+/**
+ * tcp_test_setup()
+ */
+int tcp_test_setup(void)
+{
+    etch_apr_mempool = g_apr_mempool;
+    listener = etchconn_create_listener(TEST_IP, TEST_PORT, 5, 5, g_apr_mempool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(listener);
+    
+    listener->conn.on_accepted = got_accepted;
+
+    tcpconn = etchconn_create_tcp(TEST_IP, TEST_PORT, 5, g_apr_mempool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(listener);
+
+    /* create another connection to listener */
+    tcpconn2 = etchconn_create_tcp(TEST_IP, TEST_PORT, 5, g_apr_mempool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcpconn2);
+    
+    memset(accepted_connections, 0, NUM_TEST_CONNECTIONS * sizeof(void*));
+
+    return 0;
+}
+
+
+/**
+ * tcp_test_teardown()
+ */
+int tcp_test_teardown(void)
+{
+    int i = 0;  /* memory leaks up the yingyang here - wrappers not destroyed */
+    etchconn_destroy((etchconn*)tcpconn); /* TODO call object dtor instead */
+    etchconn_destroy((etchconn*)tcpconn2);
+    etchconn_destroy((etchconn*)listener);
+    
+    for(; i < NUM_TEST_CONNECTIONS; i++)
+    {
+         etch_tcpconn* connection = accepted_connections[i];
+         if (NULL == connection) break;
+         
+         etch_tcpconn_destroy(connection);  
+
+         accepted_connections[i] = NULL;
+    }
+
+    return 0;
+}
+
+
+/**
+ * test_tcp_connection()
+ */
+void test_tcp_connection(void)
+{
+    int i=0, result=0;
+    char data[] = "this is testSimple data";
+    const int ITERS = 50;
+
+    result = tcp_test_setup();
+
+    result = etchconn_start((etchconn*)listener);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = etchmon_wait_until_equal(listener->conn.monitor, /* HANGS HERE */
+        ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+
+    result = etchconn_start((etchconn*)tcpconn);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = etchmon_wait_until_equal(tcpconn->conn.monitor, 
+        ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+
+    CU_ASSERT_EQUAL(result,0);
+
+    for(i = 0; i < ITERS; i++)
+    {
+        result = etchconn_send_tcp((etchconn*)tcpconn, data, 
+            (strlen(data)+1)*sizeof(char));
+
+        CU_ASSERT_EQUAL(result,0);
+        etch_sleep(100);
+    }
+
+    etch_sleep(1000);
+
+    result = etchconn_stop((etchconn*)tcpconn);
+    CU_ASSERT_EQUAL(result,0);
+
+    etch_sleep(1000);
+    CU_ASSERT_PTR_NOT_NULL(accepted_connections[0]);
+
+    result = etchconn_stop((etchconn*)accepted_connections[0]);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = etchconn_stop((etchconn*)listener);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = tcp_test_teardown();
+}
+
+
+/**
+ * test_more_connections()
+ */
+void test_more_connections(void)
+{
+    int i=0, result=0;
+    const int ITERS = 100;
+    char data[]  = "CONN1 test_more_connections";
+    char data2[] = "CONN2 test_more_connections";
+
+    result = tcp_test_setup();
+
+    result = etchconn_start((etchconn*)listener);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = etchmon_wait_until_equal(listener->conn.monitor, 
+        ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = etchconn_start((etchconn*)tcpconn);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    /* create another connection to listener */
+    result = etchconn_start((etchconn*) tcpconn2);
+    CU_ASSERT_EQUAL_FATAL(result,0)
+
+    result = etchmon_wait_until_equal(tcpconn->conn.monitor,  
+        ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT_EQUAL(result,0)
+
+    result = etchmon_wait_until_equal(tcpconn2->conn.monitor, 
+        ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT_EQUAL(result,0)
+
+    for(i = 0; i < ITERS; i++)
+    {
+        result = etchconn_send_tcp((etchconn*)tcpconn,  data, 
+            (strlen(data) +1)*sizeof(char));
+        CU_ASSERT_EQUAL(result,0)
+
+        result = etchconn_send_tcp((etchconn*)tcpconn2, data2,
+            (strlen(data2)+1)*sizeof(char));
+        CU_ASSERT_EQUAL(result,0)
+
+        etch_sleep(10);
+    }
+
+    etch_sleep(1000);
+
+    result = etchconn_stop((etchconn*)tcpconn);
+    CU_ASSERT_EQUAL(result,0)
+
+    result = etchconn_stop((etchconn*)tcpconn2);
+    CU_ASSERT_EQUAL(result,0)
+
+    etch_sleep(1000);
+    CU_ASSERT_PTR_NOT_NULL(accepted_connections[0]);
+
+    result = etchconn_stop((etchconn*)accepted_connections[0]);
+    CU_ASSERT_EQUAL(result,0)
+
+    CU_ASSERT_PTR_NOT_NULL(accepted_connections[1]);
+
+    result = etchconn_stop((etchconn*)accepted_connections[1]);
+    CU_ASSERT_EQUAL(result,0)
+
+    result = etchconn_stop((etchconn*)listener);
+    CU_ASSERT_EQUAL(result,0)
+
+    result = tcp_test_teardown();
+}
+
+/* ============================================================================
+ * END TCP TESTS
+ * ============================================================================
+ */
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    char c=0;
+    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_tcpconn");
+    ps = CU_add_suite("suite_tcpconn", init_suite, clean_suite);
+        
+    //CU_add_test(ps, "createAndDestroy", testCreateAndDestroy);
+    //CU_add_test(ps, "set", testSet);
+    //CU_add_test(ps, "waittimeout", testWaitTimeout);
+    //CU_add_test(ps, "setAndWait", testSetAndWait);
+    //CU_add_test(ps, "testSetAndWaitUntilEqual", testSetAndWaitUntilEqual);
+
+    CU_add_test(ps, "simple tcp connection", test_tcp_connection);
+
+    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(!c) c = _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/transport/test_transport.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_transport.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_transport.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_transport.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,471 @@
+/* $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_transport.c
+ * test delivery service etc
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_transport.h"  
+#include "etchthread.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 "etchmap.h"
+#include "etchlog.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+default_value_factory* new_bogus_valuefactory();
+
+
+/* - - - - - - - - - - - - - - 
+ * 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 FAKEID_TYPE_ADD         1 
+#define FAKEID_TYPE_ADD_RESULT  2 
+#define FAKEID_FIELD_X          3 
+#define FAKEID_FIELD_Y          4
+#define FAKEID_FIELD_RESULT     5
+#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_IMPL_TP;
+unsigned short CLASSID_MY_IMPL_SM;
+
+etch_resources*         g_my_resources;
+default_value_factory*  g_my_vf;
+etch_who*               g_who;
+
+/**
+ * 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();
+    CLASSID_MY_IMPL_TP = get_dynamic_classid();
+    CLASSID_MY_IMPL_SM = get_dynamic_classid();  
+
+    g_my_vf = new_bogus_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 = get_etch_transport_resources(NULL);
+    etch_resources_add(g_my_resources, ETCH_RESXKEY_MSGIZER_VALUFACT, (objmask*) g_my_vf); 
+   
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE), TRUE);
+
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+    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_who) 
+        g_who->destroy(g_who);
+
+    g_my_resources = NULL;
+    g_my_vf = NULL;
+    g_who = NULL;
+
+    etchvf_free_builtins(); 
+}
+
+
+/* - - - - - - - - - -
+ * 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_add;
+    etch_type*      mt_add_result;
+    etch_field*     mf_x;
+    etch_field*     mf_y;
+    etch_field*     mf_result;
+
+} 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_add);
+        destroy_static_type(impl->mt_add_result);
+        destroy_static_field(impl->mf_x); 
+        destroy_static_field(impl->mf_y); 
+        destroy_static_field(impl->mf_result);  
+    }
+
+    return destroy_objectex((objmask*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for inheriting value factory 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_add = new_static_type(L"add");
+    impl->mt_add_result = new_static_type(L"add_result");
+    impl->mf_x = new_static_field(L"x");
+    impl->mf_y = new_static_field(L"y");
+    impl->mf_result = new_static_field(L"xresult");
+
+    /* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
+    impl->mt_add->id        = FAKEID_TYPE_ADD;
+    impl->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
+    impl->mf_x->id          = FAKEID_FIELD_X;
+    impl->mf_y->id          = FAKEID_FIELD_Y;
+    impl->mf_result->id     = FAKEID_FIELD_RESULT;
+
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_x), 
+        (objmask*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_y), 
+        (objmask*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(builtins._mf__message_id), 
+        (objmask*) etchvtor_int64_get(0));
+
+    etchtype_put_validator(impl->mt_add_result, clone_field(impl->mf_result), 
+        (objmask*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__message_id), 
+        (objmask*) etchvtor_int64_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__in_reply_to), 
+        (objmask*) etchvtor_int64_get(0));
+
+    return impl;
+}
+
+
+/**
+ * new_bogus_valuefactory()
+ * constructor for value factory version 2 inheriting from default_value_factory
+ */
+default_value_factory* new_bogus_valuefactory()
+{
+    etchparentinfo* inheritlist = NULL;
+    my_valufactory_impl* impl = NULL;
+
+    /* establish global dynamic class IDs for the custom vf. 
+     * these global objects are generated by the etch compiler.
+     */
+    const unsigned short class_id_vf = CLASSID_MY_VF? CLASSID_MY_VF: 
+         (CLASSID_MY_VF = get_dynamic_classid());
+
+    const unsigned short class_id_vf_vtab = CLASSID_MY_VF_VTAB? CLASSID_MY_VF_VTAB: 
+         (CLASSID_MY_VF_VTAB = get_dynamic_classid());
+
+    /* instantiate the new value factory.  
+     * this vf does NOT own its type maps since we supply them here. 
+     * however if we wanted to abandon ownership, we could clear the   
+     * vf.is_own_types and vf.is_own_class_to_type flags here.
+     */    
+    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_MY_VF_VTAB);
+    inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    g_my_vf->class_id = CLASSID_MY_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_add);
+    g_my_vf->vtab->add_type(g_my_vf, impl->mt_add_result);
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * 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_tcpds_construction()
+ * test tcp delivery service constructor and destructor
+ */
+void test_tcpds_construction(void)
+{
+    setup_this_test();
+
+    do 
+    {   etch_tcp_delivery_service* tcpds = NULL;
+        etch_tcp_connection* nullconnection = NULL;
+        /* h_url* url = new_url(L"http://www.cisco.com:9999/cuae:?Messagizer.format=binary"); */
+        /* messagizer format is supplied in resource map - see get_etch_transport_resources() */
+        etch_url* url = new_url(L"http://www.cisco.com:9999/cuae"); 
+        etch_server_factory* impl_factory = new_server_factory (NULL, NULL, NULL, NULL);
+        impl_factory->in_resx = g_my_resources;
+
+        tcpds = new_tcp_delivery_service(url, (etch_factory_params*) impl_factory, nullconnection);  
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(tcpds);  
+
+        tcpds->destroy(tcpds);    
+
+        url->destroy(url);
+        impl_factory->destroy(impl_factory);
+
+    } 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_construction()
+ * test delivery service constructor and destructor
+ */
+void test_transport_construction(void)
+{
+    setup_this_test();
+
+    do 
+    {   etch_server_factory* impl_factory = new_server_factory (NULL, NULL, NULL, NULL);
+        etch_tcp_connection* nullconnection = NULL;
+        i_delivery_service* ds = NULL;
+        impl_factory->in_resx = g_my_resources;
+
+        ds = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+            (etch_factory_params*) impl_factory, nullconnection);  
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(ds);  
+
+        ds->destroy(ds); /* destroys transport implementation via interface */
+        impl_factory->destroy(impl_factory);
+
+    } 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_transport");
+    ps = CU_add_suite("transport test suite", init_suite, clean_suite);
+    etch_watch_id = 0; 
+        
+    CU_add_test(ps, "test test setup and teardown", test_setup);
+    CU_add_test(ps, "test tcp delivery service constructor", test_tcpds_construction);
+    CU_add_test(ps, "test transport constructor", test_transport_construction);
+       
+    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/transport/test_url.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_url.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_url.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_url.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,542 @@
+/* $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_url.c -- test etch_url
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_url.h"   
+#include "etchmap.h"    
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etchthread.h"
+#include "etch_global.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+int g_is_automated_test, g_bytes_allocated;
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+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;
+}
+
+/*
+ * 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()
+{
+    etch_apr_mempool = g_apr_mempool;
+    return 0;
+}
+
+int this_teardown()
+{    
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * tests
+ * - - - - - - - - - - - - - -
+ */
+
+/* 
+ * test_parse_1
+ */
+void test_parse_1(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"www.cisco.com";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, ETCH_URL_DEFAULT_SCHEME);
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, RAWURL);
+    CU_ASSERT_EQUAL(result,0); 
+
+    url->destroy(url);
+
+    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_parse_2
+ */
+void test_parse_2(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://www.cisco.com/cuae";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    url->destroy(url);
+
+    g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test_parse_3
+ */
+void test_parse_3(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    url->destroy(url);
+
+    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_parse_4
+ */
+void test_parse_4(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://administrator:metreos@www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    url->destroy(url);
+
+    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_parse_5
+ * since colon is both scheme and username:password delimiter
+ * ensure we can omit scheme and include password
+ */
+void test_parse_5(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"administrator:metreos@www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    url->destroy(url);
+
+    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_parse_6
+ */
+void test_parse_6(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"tcp://administrator:metreos@localhost:10000/defUri;param1;param2?term1=true&term2=false#defFragment";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"tcp");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"localhost");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 10000;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"defUri");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = etchurl_paramcount(url);
+    CU_ASSERT_EQUAL(result,2); 
+
+    result = etchurl_termcount(url);
+    CU_ASSERT_EQUAL(result,2);
+
+    do 
+    {   etch_iterator* iterator = etchurl_get_params(url);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+
+        while(iterator->has_next(iterator))
+        {   int matches = 0;
+            etch_string* val = (etch_string*) iterator->current_value;
+            wchar_t* param = val? val->v.valw: NULL;
+            if (param && 0 == wcscmp(param, L"param1")) matches++;
+            if (param && 0 == wcscmp(param, L"param2")) matches++;
+            CU_ASSERT_EQUAL(matches,1); 
+            iterator->next(iterator);
+        }
+        iterator->destroy(iterator);
+    } while(0);
+
+    do 
+    {   etch_iterator iterator;
+        set_iterator(&iterator, url->terms, &url->terms->iterable);
+
+        while(iterator.has_next(&iterator))
+        {   int keymatches = 0, valmatches = 0;
+            wchar_t* key = (wchar_t*) iterator.current_key;
+            etch_string* valobj = (etch_string*) iterator.current_value;
+            wchar_t* val = valobj? valobj->v.valw: NULL;
+            if (key && 0 == wcscmp(key, L"term1")) keymatches++;
+            if (key && 0 == wcscmp(key, L"term2")) keymatches++;
+            CU_ASSERT_EQUAL(keymatches,1); 
+            if (val && 0 == wcscmp(val, L"false")) valmatches++;
+            if (val && 0 == wcscmp(val, L"true"))  valmatches++;
+            CU_ASSERT_EQUAL(valmatches,1); 
+            iterator.next(&iterator);
+        }
+    } while(0);
+
+    url->destroy(url);
+
+    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_parse_7
+ * test a url with duplicate term names
+ */
+void test_parse_7(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"tcp://administrator:metreos@localhost:10000/defUri;param1;param2?term1=true&term1=false";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"tcp");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"localhost");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 10000;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"defUri");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = etchurl_paramcount(url);
+    CU_ASSERT_EQUAL(result,2); 
+
+    /* since terms had same name, the two terms should now be collected into a set, 
+     * therefore the count (at top level) should be 1. this is of course based
+     * on our omniscient knowledge of the url content */
+    result = etchurl_termcount(url);
+    CU_ASSERT_EQUAL(result,1); 
+
+    do  /* iterate all params */
+    {   etch_iterator* iterator = etchurl_get_params(url);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+
+        while(iterator->has_next(iterator))
+        {   int matches = 0;
+            etch_string* val = (etch_string*) iterator->current_value;
+            wchar_t* param = val? val->v.valw: NULL;
+            if (param && 0 == wcscmp(param, L"param1")) matches++;
+            if (param && 0 == wcscmp(param, L"param2")) matches++;
+            CU_ASSERT_EQUAL(matches,1); 
+
+            iterator->next(iterator);
+        }
+
+        iterator->destroy(iterator);
+
+    } while(0);
+
+    do  /* iterate all terms */
+    {   etch_iterator iterator1;
+        set_iterator(&iterator1, url->terms, &url->terms->iterable);
+
+        /* this is hard coded base on our knowledge of the url content. 
+         * there should be one term in the term map with the value "term1",
+         * and its value will be a set whose two members are etch_string 
+         * objects having values of "true" and "false"
+         */
+        while(iterator1.has_next(&iterator1))
+        {    
+            etch_iterator iterator2;
+            wchar_t*  key    = (wchar_t*) iterator1.current_key;
+            etch_set* setobj = (etch_set*)iterator1.current_value;
+            CU_ASSERT_EQUAL_FATAL(is_etch_set(setobj), TRUE);
+
+            result = etchmap_count(setobj);
+            CU_ASSERT_EQUAL(result, 2);
+
+            set_iterator(&iterator2, setobj, &setobj->iterable);
+
+            while(iterator2.has_next(&iterator2))
+            {
+                int matches = 0;
+                wchar_t* val = 0;
+                etch_string* setmember = iterator2.current_key;
+                CU_ASSERT_EQUAL_FATAL(is_etch_string(setmember), TRUE);
+                val = setmember->v.valw;
+                if (val && 0 == wcscmp(val, L"true"))  matches++;
+                if (val && 0 == wcscmp(val, L"false")) matches++;
+                CU_ASSERT_EQUAL(matches,1); 
+
+                iterator2.next(&iterator2);
+            }
+            
+            iterator1.next(&iterator1);
+        }
+
+    } while(0);
+
+    url->destroy(url);
+
+    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[])
+{
+    char c=0;
+    CU_pSuite pSuite = 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_url");
+    pSuite = CU_add_suite("suite_url", init_suite, clean_suite);
+    etch_watch_id = 0;
+    etch_watch_addr = 0; // 0x4421c8;
+
+    CU_add_test(pSuite, "test parse 1", test_parse_1); 
+    CU_add_test(pSuite, "test parse 2", test_parse_2); 
+    CU_add_test(pSuite, "test parse 3", test_parse_3); 
+    CU_add_test(pSuite, "test parse 4", test_parse_4); 
+    CU_add_test(pSuite, "test parse 5", test_parse_5);
+    CU_add_test(pSuite, "test parse 6", test_parse_6);
+    CU_add_test(pSuite, "test parse 7", test_parse_7);
+
+    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(!c) c = _getch(); wprintf(L"\n"); }     
+    CU_cleanup_registry();
+    return CU_get_error(); 
+}
+