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();
+}
+