Commits

Daniel Poelzleithner committed 1969563

added and fixed the old unittestes. still messy :-)
more work on config and fixed the usage of some lua objects

Comments (0)

Files changed (8)

     option 'storage_backend' 'tc'
     option 'storage_size' '1000'
     option 'thread_num' 2
-    option 'wait_timeout' 3600
+    option 'wait_timeout' 3601
     option 'merge_strategy' 'network_plus_local'
 
 config 'mapping' 'dns'
     list mapping '02:3'
 
 config 'backend' 'static'
-    option 'enabled' 'on'
+    option 'enabled' 'off'
     list 'ip4' '127.0.0.1:2344'
 
 config 'plugin' 'dns'
-    option 'enabled' 'on'
+    option 'enabled' 'off'
     option 'port' '54'
 
 

src/CMakeLists.txt

 
 add_library(libhash STATIC hash.c lookup3.c)
 add_library(libbackend STATIC file_backend.c tc_backend.c backends.c)
-target_link_libraries(libbackend tokyocabinet pthread uci ucimap)
+target_link_libraries(libbackend tokyocabinet pthread uci)
 
 target_link_libraries(dssd dnet libhash libbackend ${LUA_LIBRARIES})

src/backends/tests.lua

-print("runnig static")
-print(uci)
-print(dssd_config)
+print("runnig tests")
 
-dssd.log(dssd.LOG_NOTICE, "testing log\n")
+package.path = package.path .. ";./tests/lua/?.lua;"
+
+require('tests.lua.test_dssd')
+
+dssd.log(dssd.LOG_NOTICE, "testing log\n")
+
 */
 }
 
+static int wait_for_threads() {
+    //pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+    //void *(*start_routine)(void*), void *arg);
+    int rv;
+	struct list_head *p;
+    struct uci_backend_config *backend;
+    struct lua_thread_param *param;
+    
+	list_for_each(p, &dssd_config_backend) {
+        backend = list_entry(p, struct uci_backend_config, list);
+        if(backend->thread)
+            pthread_join(*backend->thread, NULL);
+    }
+}
+
+
 int main(int argc, char *argv[])
 {
 	struct uci_package *pkg;
     start_lua_threads();
 
     //dnet_give_up_control(node);
-    sleep(1);
+    //sleep(1);
+    wait_for_threads();
 
     dssd_log(DNET_LOG_INFO, "exit dssd daemon normally\n");
 
 {
   struct dnet_config *dcp;
   luaL_checktype(L, index, LUA_TUSERDATA);
-  dcp = (struct dnet_config*)luaL_checkudata(L, index, DNET_META_CONFIG);
+  dcp = *(struct dnet_config **)luaL_checkudata(L, index, DNET_META_CONFIG);
 
   if (dcp == NULL) luaL_typerror(L, index, DNET_META_CONFIG);
   return dcp;
 {
   struct dnet_node *dcp;
   luaL_checktype(L, index, LUA_TUSERDATA);
-  dcp = (struct dnet_node *)luaL_checkudata(L, index, DNET_META_NODE);
+  dcp = *(struct dnet_node **)luaL_checkudata(L, index, DNET_META_NODE);
 
   if (dcp == NULL) luaL_typerror(L, index, DNET_META_NODE);
   return dcp;
 
 static int dssdL_log(lua_State *L) {
     int mask = luaL_checkinteger(L, -2);
-	const char *data = luaL_checkstring(L, -1);
-    
+    const char *data = luaL_checkstring(L, -1);
+
     dssd_log_raw(mask, (char *)data);
 }
 
 static int dnetL_config_new(lua_State *L)
 {
     // test for optional options trough tables
-    struct dnet_config *dc = (struct dnet_config *)lua_newuserdata(L, sizeof(struct dnet_config));
+    struct dnet_config **dcp = (struct dnet_config **)lua_newuserdata(L, sizeof(struct dnet_config *));
+    *dcp = malloc(sizeof(struct dnet_config));
+    struct dnet_config *dc = *dcp;
     memset(dc, 0, sizeof(struct dnet_config));
+    dc->family = dssd_server_config->family;
+    dc->sock_type = dssd_server_config->sock_type;
+    dc->wait_timeout = dssd_server_config->wait_timeout;
+    dc->log_mask = dssd_server_config->log_mask;
     //memset(dc->id, 1, sizeof(DNET_ID_SIZE));
     luaL_getmetatable(L, DNET_META_CONFIG);
     lua_setmetatable(L, -2);
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
 };
 
-char *id_to_hexstring(unsigned char *id[DNET_ID_SIZE]) {
+char *id_to_hexstring(struct dnet_config *dc) {
     /*
     convert a dnet_config id into hex to be passed into
     lua.
     char *rv = malloc(DNET_ID_SIZE*2+1);
     memset(rv, 0, DNET_ID_SIZE*2+1);
     for(i = 0; i < DNET_ID_SIZE; i++) {
-        rv[2*i]   = dnet__bin2hex[(*id[i] & 0xf0) >> 4];
-        rv[2*i+1] = dnet__bin2hex[(*id[i] & 0x0f)];
+        rv[2*i]   = dnet__bin2hex[((dc->id)[i] & 0xf0) >> 4];
+        rv[2*i+1] = dnet__bin2hex[((dc->id)[i] & 0x0f)];
     }
     return rv;
 
 {
     // test for optional options trough tables
     struct dnet_config *dc = check_dnet_config(L, -1);
-    struct dnet_node *dn = (struct dnet_node *)lua_newuserdata(L, sizeof(void *));
+    struct dnet_node **dn = (struct dnet_node **)lua_newuserdata(L, sizeof(void *));
     //memset(dc->id, 1, sizeof(DNET_ID_SIZE));
     luaL_getmetatable(L, DNET_META_NODE);
     lua_setmetatable(L, -2);
-    dn = dnet_node_create(dc);
+    *dn = dnet_node_create(dc);
     return 1;
 }
 
     // test for optional options trough tables
     struct dnet_config *dc = check_dnet_config(L, -2);
     const char *key = luaL_checkstring(L, -1);
+    char *tmp = NULL;
 
 	if (!strcmp(key, "id")) {
-        lua_pushstring(L, id_to_hexstring(&dc->id));
+        tmp = id_to_hexstring(dc);
+        lua_pushstring(L, tmp);
+        free(tmp);
 	} else if (!strcmp(key, "sock_type")) {
         lua_pushinteger(L, dc->sock_type);
 	} else if (!strcmp(key, "proto")) {
 	lua_pushinteger(L, DNET_LOG_DSA);
 	lua_setfield(L, -2, "LOG_DSA");
 
+    // some usefull constants
+	lua_pushinteger(L, PF_INET);
+	lua_setfield(L, -2, "FAMILY_IPV4");
+
+	lua_pushinteger(L, PF_INET6);
+	lua_setfield(L, -2, "FAMILY_IPV6");
 
     // push some usefull constants
 
 void *start_lua_thread (void *ptr)
 {
     struct lua_thread_param *param = ptr;
-    struct uci_context **u;
+    void **u;
     int exec_len = strlen(param->lua_file)+30;
     char *exec = malloc(exec_len);
     lua_State *L = param->lua_state;
 
     lua_setfield(L, -2, "path");  
     //lua_pop(L, 1);
-    luaL_dostring (L, "require(\"uci\")");
+    lua_getglobal(L, "require");
+    lua_pushliteral(L, "uci");
+stackDump(L, 0);
+
+    lua_call(L, 1, 0);
+    
+    //luaL_dostring (L, "require(\"uci\")");
     
     luaopen_libdnet_lua(L);
     
+
+    // prepare exported server data
+    lua_newtable(L);
+    
     // import uci module and prepare for
+stackDump(L, 0);
+
     u = lua_newuserdata(L, sizeof(struct uci_context *));
 	luaL_getmetatable(L, "uci.meta");
 	lua_setmetatable(L, -2);
+stackDump(L, 0);
 
 	*u = dssd_uci_context;
     
-    lua_setglobal(L, "dssd_config");
+    lua_setfield(L, -2, "uci_context");
+
+    //struct dnet_config *dc = (struct dnet_config *)lua_newuserdata(L, sizeof(struct dnet_config));
+    u = lua_newuserdata(L, sizeof(struct dnet_config *));
+	luaL_getmetatable(L, DNET_META_CONFIG);
+	lua_setmetatable(L, -2);
+
+	*u = dssd_server_config;
+
+    lua_setfield(L, -2, "config");
+
+    u = lua_newuserdata(L, sizeof(struct dnet_node *));
+	luaL_getmetatable(L, DNET_META_NODE);
+	lua_setmetatable(L, -2);
+
+	*u = dssd_server_node;
+
+    lua_setfield(L, -2, "node");
+
+    lua_setglobal(L, "dssd_server");
     
 /*    luaL_newmetatable(L, "dssd");
 
     
 	list_for_each(p, &dssd_config_backend) {
         backend = list_entry(p, struct uci_backend_config, list);
+        if(!backend->enabled)
+            continue;
         dssd_log(DNET_LOG_INFO, "load backend: %s\n", backend->name);
         backend->thread = malloc(sizeof(pthread_t));
         param = malloc(sizeof(struct lua_thread_param));
 
     out = strdup("prefer_network");
 
-   printf("parse %s\n", str);
+   printf("parse %s\n", *str);
 
  	return 0;
 }

tests/lua/luaunit.lua

+--[[ 
+		luaunit.lua
+
+Description: A unit testing framework
+Homepage: http://phil.freehackers.org/luaunit/
+Initial author: Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
+Lot of improvements by Philippe Fremy <phil@freehackers.org>
+Version: 1.3
+License: X11 License, see LICENSE.txt
+
+Changes between 1.3 and 1.2a:
+- port to lua 5.1
+- use orderedPairs() to iterate over a table in the right order
+- change the order of expected, actual in assertEquals() and the default value of
+  USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS. This can be adjusted with
+  USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS.
+
+Changes between 1.2a and 1.2:
+- fix: test classes were not run in the right order
+
+Changes between 1.2 and 1.1:
+- tests are now run in alphabetical order
+- fix a bug that would prevent all tests from being run
+
+Changes between 1.1 and 1.0:
+- internal variables are not global anymore
+- you can choose between assertEquals( actual, expected) or assertEquals(
+  expected, actual )
+- you can assert for an error: assertError( f, a, b ) will assert that calling
+  the function f(a,b) generates an error
+- display the calling stack when an error is spotted
+- a dedicated class collects and displays the result, to provide easy
+  customisation
+- two verbosity level, like in python unittest
+]]--
+
+argv = arg
+
+--[[ Some people like assertEquals( actual, expected ) and some people prefer 
+assertEquals( expected, actual ).
+
+]]--
+USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS = true
+
+function assertError(f, ...)
+	-- assert that calling f with the arguments will raise an error
+	-- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
+	local has_error, error_msg = not pcall( f, ... )
+	if has_error then return end 
+	error( "No error generated", 2 )
+end
+
+function assertEquals(actual, expected)
+	-- assert that two values are equal and calls error else
+	if  actual ~= expected  then
+		local function wrapValue( v )
+			if type(v) == 'string' then return "'"..v.."'" end
+			return tostring(v)
+		end
+		if not USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS then
+			expected, actual = actual, expected
+		end
+
+		local errorMsg
+		if type(expected) == 'string' then
+			errorMsg = "\nexpected: "..wrapValue(expected).."\n"..
+                             "actual  : "..wrapValue(actual).."\n"
+		else
+			errorMsg = "expected: "..wrapValue(expected)..", actual: "..wrapValue(actual)
+		end
+		print (errorMsg)
+		error( errorMsg, 2 )
+	end
+end
+
+function assertNotEquals(actual, expected)
+	-- assert that two values are equal and calls error else
+	if  actual == expected  then
+		local function wrapValue( v )
+			if type(v) == 'string' then return "'"..v.."'" end
+			return tostring(v)
+		end
+		if not USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS then
+			expected, actual = actual, expected
+		end
+
+		local errorMsg
+		if type(expected) == 'string' then
+			errorMsg = "\nexpected: "..wrapValue(expected).."\n"..
+                             "actual  : "..wrapValue(actual).."\n"
+		else
+			errorMsg = "expected: "..wrapValue(expected)..", actual: "..wrapValue(actual)
+		end
+		print (errorMsg)
+		error( errorMsg, 2 )
+	end
+end
+
+
+assert_equals = assertEquals
+assert_error = assertError
+
+function wrapFunctions(...)
+	-- Use me to wrap a set of functions into a Runnable test class:
+	-- TestToto = wrapFunctions( f1, f2, f3, f3, f5 )
+	-- Now, TestToto will be picked up by LuaUnit:run()
+	local testClass, testFunction
+	testClass = {}
+	local function storeAsMethod(idx, testName)
+		testFunction = _G[testName]
+		testClass[testName] = testFunction
+	end
+	table.foreachi( {...}, storeAsMethod )
+	return testClass
+end
+
+function __genOrderedIndex( t )
+    local orderedIndex = {}
+    for key,_ in pairs(t) do
+        table.insert( orderedIndex, key )
+    end
+    table.sort( orderedIndex )
+    return orderedIndex
+end
+
+function orderedNext(t, state)
+	-- Equivalent of the next() function of table iteration, but returns the
+	-- keys in the alphabetic order. We use a temporary ordered key table that
+	-- is stored in the table being iterated.
+
+    --print("orderedNext: state = "..tostring(state) )
+    if state == nil then
+        -- the first time, generate the index
+        t.__orderedIndex = __genOrderedIndex( t )
+        key = t.__orderedIndex[1]
+        return key, t[key]
+    end
+    -- fetch the next value
+    key = nil
+    for i = 1,table.getn(t.__orderedIndex) do
+        if t.__orderedIndex[i] == state then
+            key = t.__orderedIndex[i+1]
+        end
+    end
+
+    if key then
+        return key, t[key]
+    end
+
+    -- no more value to return, cleanup
+    t.__orderedIndex = nil
+    return
+end
+
+function orderedPairs(t)
+    -- Equivalent of the pairs() function on tables. Allows to iterate
+    -- in order
+    return orderedNext, t, nil
+end
+
+-------------------------------------------------------------------------------
+UnitResult = { -- class
+	failureCount = 0,
+	testCount = 0,
+	errorList = {},
+	currentClassName = "",
+	currentTestName = "",
+	testHasFailure = false,
+	verbosity = 1
+}
+	function UnitResult:displayClassName()
+		print( '>>>>>>>>> '.. self.currentClassName )
+	end
+
+	function UnitResult:displayTestName()
+		if self.verbosity > 0 then
+			print( ">>> ".. self.currentTestName )
+		end
+	end
+
+	function UnitResult:displayFailure( errorMsg )
+		if self.verbosity == 0 then
+			io.stdout:write("F")
+		else
+			print( errorMsg )
+			print( 'Failed' )
+		end
+	end
+
+	function UnitResult:displaySuccess()
+		if self.verbosity > 0 then
+			--print ("Ok" )
+		else 
+			io.stdout:write(".")
+		end
+	end
+
+	function UnitResult:displayOneFailedTest( failure )
+		testName, errorMsg = unpack( failure )
+		print(">>> "..testName.." failed")
+		print( errorMsg )
+	end
+
+	function UnitResult:displayFailedTests()
+		if table.getn( self.errorList ) == 0 then return end
+		print("Failed tests:")
+		print("-------------")
+		table.foreachi( self.errorList, self.displayOneFailedTest )
+		print()
+	end
+
+	function UnitResult:displayFinalResult()
+		print("=========================================================")
+		self:displayFailedTests()
+		local failurePercent, successCount
+		if self.testCount == 0 then
+			failurePercent = 0
+		else
+			failurePercent = 100 * self.failureCount / self.testCount
+		end
+		successCount = self.testCount - self.failureCount
+		print( string.format("Success : %d%% - %d / %d",
+			100-math.ceil(failurePercent), successCount, self.testCount) )
+		return self.failureCount
+    end
+
+	function UnitResult:startClass(className)
+		self.currentClassName = className
+		self:displayClassName()
+	end
+
+	function UnitResult:startTest(testName)
+		self.currentTestName = testName
+		self:displayTestName()
+        self.testCount = self.testCount + 1
+		self.testHasFailure = false
+	end
+
+	function UnitResult:addFailure( errorMsg )
+		self.failureCount = self.failureCount + 1
+		self.testHasFailure = true
+		table.insert( self.errorList, { self.currentTestName, errorMsg } )
+		self:displayFailure( errorMsg )
+	end
+
+	function UnitResult:endTest()
+		if not self.testHasFailure then
+			self:displaySuccess()
+		end
+	end
+
+-- class UnitResult end
+
+
+LuaUnit = {
+	result = UnitResult
+}
+	-- Split text into a list consisting of the strings in text,
+	-- separated by strings matching delimiter (which may be a pattern). 
+	-- example: strsplit(",%s*", "Anna, Bob, Charlie,Dolores")
+	function LuaUnit.strsplit(delimiter, text)
+		local list = {}
+		local pos = 1
+		if string.find("", delimiter, 1) then -- this would result in endless loops
+			error("delimiter matches empty string!")
+		end
+		while 1 do
+			local first, last = string.find(text, delimiter, pos)
+			if first then -- found?
+				table.insert(list, string.sub(text, pos, first-1))
+				pos = last+1
+			else
+				table.insert(list, string.sub(text, pos))
+				break
+			end
+		end
+		return list
+	end
+
+	function LuaUnit.isFunction(aObject) 
+		return 'function' == type(aObject)
+	end
+
+	function LuaUnit.strip_luaunit_stack(stack_trace)
+		stack_list = LuaUnit.strsplit( "\n", stack_trace )
+		strip_end = nil
+		for i = table.getn(stack_list),1,-1 do
+			-- a bit rude but it works !
+			if string.find(stack_list[i],"[C]: in function `xpcall'",0,true)
+				then
+				strip_end = i - 2
+			end
+		end
+		if strip_end then
+			table.setn( stack_list, strip_end )
+		end
+		stack_trace = table.concat( stack_list, "\n" )
+		return stack_trace
+	end
+
+    function LuaUnit:runTestMethod(aName, aClassInstance, aMethod)
+		local ok, errorMsg
+		-- example: runTestMethod( 'TestToto:test1', TestToto, TestToto.testToto(self) )
+		LuaUnit.result:startTest(aName)
+
+		-- run setUp first(if any)
+		if self.isFunction( aClassInstance.setUp) then
+				aClassInstance:setUp()
+		end
+
+		local function err_handler(e)
+			return e..'\n'..debug.traceback()
+		end
+
+		-- run testMethod()
+        ok, errorMsg = xpcall( aMethod, err_handler )
+		if not ok then
+			errorMsg  = self.strip_luaunit_stack(errorMsg)
+			LuaUnit.result:addFailure( errorMsg )
+        end
+
+		-- lastly, run tearDown(if any)
+		if self.isFunction(aClassInstance.tearDown) then
+			 aClassInstance:tearDown()
+		end
+
+		self.result:endTest()
+    end
+
+	function LuaUnit:runTestMethodName( methodName, classInstance )
+		-- example: runTestMethodName( 'TestToto:testToto', TestToto )
+		local methodInstance = loadstring(methodName .. '()')
+		LuaUnit:runTestMethod(methodName, classInstance, methodInstance)
+	end
+
+    function LuaUnit:runTestClassByName( aClassName )
+		-- example: runTestMethodName( 'TestToto' )
+		local hasMethod, methodName, classInstance
+		hasMethod = string.find(aClassName, ':' )
+		if hasMethod then
+			methodName = string.sub(aClassName, hasMethod+1)
+			aClassName = string.sub(aClassName,1,hasMethod-1)
+		end
+        classInstance = _G[aClassName]
+		if not classInstance then
+			error( "No such class: "..aClassName )
+		end
+
+		LuaUnit.result:startClass( aClassName )
+
+		if hasMethod then
+			if not classInstance[ methodName ] then
+				error( "No such method: "..methodName )
+			end
+			LuaUnit:runTestMethodName( aClassName..':'.. methodName, classInstance )
+		else
+			-- run all test methods of the class
+			for methodName, method in orderedPairs(classInstance) do
+			--for methodName, method in classInstance do
+				if LuaUnit.isFunction(method) and string.sub(methodName, 1, 4) == "test" then
+					LuaUnit:runTestMethodName( aClassName..':'.. methodName, classInstance )
+				end
+			end
+		end
+		print()
+	end
+
+	function LuaUnit:run(...)
+		-- Run some specific test classes.
+		-- If no arguments are passed, run the class names specified on the
+		-- command line. If no class name is specified on the command line
+		-- run all classes whose name starts with 'Test'
+		--
+		-- If arguments are passed, they must be strings of the class names 
+		-- that you want to run
+                args={...};
+		if #args > 0 then
+			table.foreachi( args, LuaUnit.runTestClassByName )
+		else 
+			if argv and #argv > 0 then
+				table.foreachi(argv, LuaUnit.runTestClassByName )
+			else
+				-- create the list before. If you do not do it now, you
+				-- get undefined result because you modify _G while iterating
+				-- over it.
+				testClassList = {}
+				for key, val in pairs(_G) do 
+					if string.sub(key,1,4) == 'Test' then 
+						table.insert( testClassList, key )
+					end
+				end
+				for i, val in orderedPairs(testClassList) do 
+						LuaUnit:runTestClassByName(val)
+				end
+			end
+		end
+		return LuaUnit.result:displayFinalResult()
+	end
+-- class LuaUnit
+

tests/lua/test_dssd.lua

+package.cpath = package.cpath .. ";./.libs/?.so"
+require('luaunit')
+
+-- http://www.keplerproject.org/luafilesystem/manual.html
+require('lfs')
+
+dnet = dssd
+
+function set(var, key, val)
+    var[key] = val
+end
+
+STARTPORT = 5222
+
+TestDnet = {} --class
+
+
+    function TestDnet:setUp()
+        -- set up tests
+		self.a = 1
+		self.s = 'hop' 
+    end
+
+    function TestDnet:test_env()
+        assertEquals(type(dssd), "table")
+        assertEquals(type(uci), "table")
+
+        assertEquals(type(dssd_server), "table")
+        assertEquals(type(dssd_server.uci_context), "userdata")
+    end
+
+    function TestDnet:test_static()
+        for w in string.gmatch(dnet.version, "%w") do
+            assertEquals(type(tonumber(w)), "number")
+        end
+        assertEquals(dnet.id_cmp(
+                     string.rep("12", dnet.id_size-1).."01", 
+                     string.rep("12", dnet.id_size-1).."00"),
+                     -1)
+        assertEquals(dnet.id_cmp(
+                     string.rep("ae", dnet.id_size), 
+                     string.rep("ae", dnet.id_size)),
+                     0)
+        assertEquals(dnet.id_cmp(
+                     string.rep("12", dnet.id_size-1).."00", 
+                     string.rep("12", dnet.id_size-1).."10"),
+                     1)
+        assertEquals(dnet.LOG_NOTICE, 1)
+        
+    end
+
+    function TestDnet:test_config()
+        dc = dnet.new_config()
+		-- dc = dnet.new_config()
+        
+        assertEquals(type (dc), "userdata" )
+        print(tostring(dc))
+        print(dc["id"])
+        print(dnet.id_size)
+        -- id must be 0 on this stage
+        assertEquals(dc['id'], string.rep("00", dnet.id_size))
+        --0000000000000000000000000000000000000000
+        dc["id"] = string.rep("12", dnet.id_size)
+        assertEquals(dc['id'], string.rep("12", dnet.id_size))
+        -- invalid tests
+        assertError(set, dc, 'id', "a3")
+        assertError(dc['id'], string.rep("ag", dnet.id_size))
+
+        assertEquals(dc['addr'], '')
+        assertEquals(dc['port'], '')
+        print("wt"..tostring(dc['wait_timeout'])..tostring(dssd_server.config.wait_timeout))
+        assertEquals(dc['wait_timeout'], dssd_server.config.wait_timeout)
+
+        dc['addr'] = nil
+        assertEquals(dc['addr'], "")
+        dc['addr'] = "myhostname"
+        assertEquals(dc['addr'], "myhostname")
+        assertError(set, dc, 'addr', assertEquals)
+
+        -- port tests
+        dc['port'] = 1
+        assertEquals(dc['port'], '1')
+        dc['port'] = nil
+        assertEquals(dc['port'], '')
+        --port accepts strings
+        --assertError(set, dc, 'port', "nonumber")
+        dc['port'] = "notanum"
+        assertEquals(dc['port'], 'notanum')
+
+        dc['port'] = 43211234
+        assertEquals(dc['port'], '43211234')
+        assertError(set, dc, 'port', "432112343")
+        dc['port'] = "1234"
+
+        assertEquals(dc['join'], 0)
+        dc['join'] = 1
+        assertEquals(dc['join'], 1)
+
+        assertEquals(dc['io_thread_num'], 0)
+        dc['io_thread_num'] = 4
+        assertEquals(dc['io_thread_num'], 4)
+
+        assertEquals(dc['hash_size'], 0)
+        dc['hash_size'] = 5
+        assertEquals(dc['hash_size'], 5)
+        
+        assertEquals(dc['max_pending'], 0)
+        dc['max_pending'] = 6
+        assertEquals(dc['max_pending'], 6)
+
+        assertEquals(dc['log_mask'], dssd_server.config.log_mask)
+        dc['log_mask'] = 7
+        assertEquals(dc['log_mask'], 7)
+
+        -- end results test
+        assertEquals(dc['port'], '1234')
+        assertEquals(dc['addr'], "myhostname")
+        assertEquals(dc['max_pending'], 6)
+        assertEquals(dc['io_thread_num'], 4)
+
+
+        dc2 = dnet.new_config()
+        assertNotEquals(dc, dc2)
+
+    end
+
+    function TestDnet:create_config(ip, port)
+        dc = dnet.new_config()
+        if port == nil then
+            STARTPORT = STARTPORT +1
+        end
+        dc['addr'] = ip or '0.0.0.0'
+        dc['port'] = port or STARTPORT
+        dc['log_mask'] = dnet.LOG_NOTICE + dnet.LOG_INFO + dnet.LOG_ERROR --+ dnet.LOG_NOTICE + dnet.LOG_ERROR + dnet.LOG_TRANS + dnet.LOG_DSA
+
+-- 	 * Socket type (SOCK_STREAM, SOCK_DGRAM and so on),
+-- 	 * a protocol (IPPROTO_TCP for example) and
+-- 	 * a family (AF_INET
+        -- we should get those static from the os but i don't think thats
+        -- in the scope of this bindings
+        dc['sock_type'] = 1 -- SOCK_STREAM
+        dc['proto'] = 6 -- IPPROTO_TCP
+        dc['family'] = 2 -- AF_INET
+
+        return dc
+    
+    end
+
+    function TestDnet:test_node()
+        dc = TestDnet:create_config(nil, 4224)
+        local node = dc:create_node()
+        dc2 = TestDnet:create_config("127.0.0.1", "4225")
+        print('Add node'..tostring(dc2))
+        node:add_state(dc2)
+        node:join()
+        print('Done')
+    end
+
+
+-- class TestDnet
+
+LuaUnit:run()