diff options
Diffstat (limited to 'unit-tests.lua')
-rw-r--r-- | unit-tests.lua | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/unit-tests.lua b/unit-tests.lua new file mode 100644 index 0000000..11dfcef --- /dev/null +++ b/unit-tests.lua @@ -0,0 +1,395 @@ +#!/usr/bin/lua +--------------------------------------------------------------------- +-- LuaLDAP test file. +-- This test will create a copy of an existing entry on the +-- directory to work on. This new entry will be modified, +-- renamed and deleted at the end. +--------------------------------------------------------------------- + +-- +DN_PAT = "^([^,=]+)%=([^,]+)%,?(.*)$" + +--------------------------------------------------------------------- +-- Print attributes. +--------------------------------------------------------------------- +function print_attrs (dn, attrs) + if not dn then + io.write ("nil\n") + return + end + io.write (string.format ("\t[%s]\n", dn)) + for name, values in pairs (attrs) do + io.write ("["..name.."] : ") + local tv = type (values) + if tv == "string" then + io.write (values) + elseif tv == "table" then + local n = table.getn (values) + for i = 1, n-1 do + io.write (values[i]..",") + end + io.write (values[n]) + end + io.write ("\n") + end +end + +--------------------------------------------------------------------- +-- clone a table. +--------------------------------------------------------------------- +function clone (tab) + local new = {} + for i, v in pairs (tab) do + new[i] = v + end + return new +end + + +--------------------------------------------------------------------- +-- checks for a value and throw an error if it is not the expected. +--------------------------------------------------------------------- +function assert2 (expected, value, msg) + if not msg then + msg = '' + else + msg = tostring(msg)..'\n' + end + local ret = assert (value == expected, + msg.."wrong value (["..tostring(value).."] instead of ".. + tostring(expected)..")") + io.write('.') + return ret +end + +--------------------------------------------------------------------- +-- object test. +--------------------------------------------------------------------- +function test_object (obj, objmethods) + -- checking object type. + assert2 ("userdata", type(obj), "incorrect object type") + -- trying to get metatable. + assert2 ("LuaLDAP: you're not allowed to get this metatable", + getmetatable(obj), "error permitting access to object's metatable") + -- trying to set metatable. + assert2 (false, pcall (setmetatable, ENV, {})) + -- checking existence of object's methods. + for i = 1, table.getn (objmethods) do + local method = obj[objmethods[i]] + assert2 ("function", type(method)) + assert2 (false, pcall (method), "no 'self' parameter accepted") + end + return obj +end + +CONN_OK = function (obj, err) + if obj == nil then + error (err, 2) + end + return test_object (obj, { "close", "add", "compare", "delete", "modify", "rename", "search", }) +end + +--------------------------------------------------------------------- +-- basic checking test. +--------------------------------------------------------------------- +function basic_test () + local ld = CONN_OK (lualdap.open_simple { uri = HOSTNAME, who = WHO, password = PASSWORD }) + assert2 (1, ld:close(), "couldn't close connection") + -- trying to close without a connection. + assert2 (false, pcall (ld.close)) + -- trying to close an invalid connection. + assert2 (false, pcall (ld.close, io.output())) + -- trying to use a closed connection. + local _,_,rdn_name,rdn_value = string.find (BASE, DN_PAT) + assert2 (false, pcall (ld.compare, ld, BASE, rdn_name, rdn_value), + "permitting the use of a closed connection") + -- it is ok to close a closed object, but nil is returned instead of 1. + assert2 (nil, ld:close()) + -- trying to connect to an invalid host. + assert2 (nil, lualdap.open_simple {uri = "unknown-server"}, "this should be an error") + -- reopen the connection. + -- first, try using TLS + local ok = lualdap.open_simple {uri = HOSTNAME, who = WHO, password = PASSWORD, starttls = true } + if not ok then + -- second, try without TLS + io.write ("\nWarning! Couldn't connect with TLS. Trying again without it.") + ok = lualdap.open_simple {uri = HOSTNAME, who = WHO, password = PASSWORD, starttls = false } + end + LD = CONN_OK (ok) + CLOSED_LD = ld + collectgarbage() +end + + +--------------------------------------------------------------------- +-- checks return value which should be a function AND also its return value. +--------------------------------------------------------------------- +function check_future (ret, method, ...) + local ok, f = pcall (method, unpack (arg)) + assert (ok, f) + assert2 ("function", type(f)) + assert2 (ret, f()) + io.write('.') +end + + +--------------------------------------------------------------------- +-- checking compare operation. +--------------------------------------------------------------------- +function compare_test () + local _,_,rdn_name,rdn_value = string.find (BASE, DN_PAT) + assert (type(rdn_name) == "string", "could not extract RDN name") + assert (type(rdn_value) == "string", "could not extract RDN value") + -- comparing against the correct value. + check_future (true, LD.compare, LD, BASE, rdn_name, rdn_value) + -- comparing against a wrong value. + check_future (false, LD.compare, LD, BASE, rdn_name, rdn_value..'_') + -- comparing against an incorrect attribute name. + check_future (nil, LD.compare, LD, BASE, rdn_name..'x', rdn_value) + -- comparing on a wrong base. + check_future (nil, LD.compare, LD, 'qwerty', rdn_name, rdn_value) + -- comparing with a closed connection. + assert2 (false, pcall (LD.compare, CLOSED_LD, BASE, rdn_name, rdn_value)) + -- comparing with an invalid userdata. + assert2 (false, pcall (LD.compare, io.output(), BASE, rdn_name, rdn_value)) +end + + +--------------------------------------------------------------------- +-- checking basic search operation. +--------------------------------------------------------------------- +function search_test_1 () + local _,_,rdn = string.find (WHO, "^([^,]+)%,.*$") + local iter = LD:search { + base = BASE, + scope = "onelevel", + sizelimit = 1, + filter = "("..rdn..")", + } + assert2 ("function", type(iter)) + collectgarbage() + CONN_OK (LD) + local dn, entry = iter () + assert2 ("string", type(dn)) + assert2 ("table", type(entry)) + collectgarbage() + assert2 ("function", type(iter)) + CONN_OK (LD) + + DN, ENTRY = LD:search { + base = BASE, + scope = "onelevel", + sizelimit = 1, + filter = "("..rdn..")", + }() + collectgarbage() + assert2 ("string", type(DN)) + assert2 ("table", type(ENTRY)) +end + + +--------------------------------------------------------------------- +-- checking add operation. +--------------------------------------------------------------------- +function add_test () + -- clone an entry. + NEW = clone (ENTRY) + local _,_,rdn_name, rdn_value, parent_dn = string.find (DN, DN_PAT) + NEW[rdn_name] = rdn_value.."_copy" + NEW_DN = string.format ("%s=%s,%s", rdn_name, NEW[rdn_name], parent_dn) + -- trying to insert an entry with a wrong connection. + assert2 (false, pcall (LD.add, CLOSED_LD, NEW_DN, NEW)) + -- trying to insert an entry with an invalid connection. + assert2 (false, pcall (LD.add, io.output(), NEW_DN, NEW)) + -- trying to insert an entry with a wrong DN. + local wrong_dn = string.format ("%s_x=%s,%s", rdn_name, NEW_DN, parent_dn) + --assert2 (nil, LD:add (wrong_dn, NEW)) + check_future (nil, LD.add, LD, wrong_dn, NEW) + -- trying to insert the clone on the LDAP data base. + check_future (true, LD.add, LD, NEW_DN, NEW) + -- trying to reinsert the clone entry on the directory. + check_future (nil, LD.add, LD, NEW_DN, NEW) +end + + +--------------------------------------------------------------------- +-- checking modify operation. +--------------------------------------------------------------------- +function modify_test () + -- modifying without connection. + assert2 (false, pcall (LD.modify, nil, NEW_DN, {})) + -- modifying with a closed connection. + assert2 (false, pcall (LD.modify, CLOSED_LD, NEW_DN, {})) + -- modifying with an invalid userdata. + assert2 (false, pcall (LD.modify, io.output(), NEW_DN, {})) + -- checking invalid DN. + assert2 (false, pcall (LD.modify, LD, {})) + -- no modification to apply. + check_future (true, LD.modify, LD, NEW_DN) + -- forgotten operation on modifications table. + local a_attr, a_value = next (ENTRY) + assert2 (false, pcall (LD.modify, LD, NEW_DN, { [a_attr] = "abc"})) + -- modifying an unknown entry. + local _,_, rdn_name, rdn_value, parent_dn = string.find (NEW_DN, DN_PAT) + local new_rdn = rdn_name..'='..rdn_value..'_' + local new_dn = string.format ("%s,%s", new_rdn, parent_dn) + check_future (nil, LD.modify, LD, new_dn) + -- trying to create an undefined attribute. + check_future (nil, LD.modify, LD, NEW_DN, {'+', unknown_attribute = 'a'}) +end + + +--------------------------------------------------------------------- +function count (tab) + local counter = 0 + for dn, entry in LD:search (tab) do + counter = counter + 1 + end + return counter +end + + +--------------------------------------------------------------------- +-- checking advanced search operation. +--------------------------------------------------------------------- +function search_test_2 () + local _,_,rdn = string.find (WHO, "^([^,]+)%,.*$") + local iter = LD:search { + base = BASE, + scope = "onelevel", + sizelimit = 1, + filter = "("..rdn..")", + } + assert2 ("function", type(iter)) + collectgarbage () + assert2 ("function", type(iter)) + local dn, entry = iter () + assert2 ("string", type(dn)) + assert2 ("table", type(entry)) + collectgarbage () + assert2 ("function", type(iter)) + iter = nil + collectgarbage () + + -- checking no search specification. + assert2 (false, pcall (LD.search, LD)) + -- checking invalid scope. + assert2 (false, pcall (LD.search, LD, { scope = 'BASE', base = BASE, })) + -- checking invalid base. + check_future (nil, LD.search, LD, { base = "invalid", scope = "base", }) + -- checking filter. + local _,_, rdn_name, rdn_value, parent_dn = string.find (NEW_DN, DN_PAT) + local filter = string.format ("(%s=%s)", rdn_name, rdn_value) + assert (count { base = BASE, scope = "subtree", filter = filter, } == 1) + -- checking sizelimit. + assert (count { base = BASE, scope = "subtree", sizelimit = 1, } == 1) + -- checking attrsonly parameter. + for dn, entry in LD:search { base = BASE, scope = "subtree", attrsonly = true, } do + for attr, value in pairs (entry) do + assert (value == true, "attrsonly failed") + end + end + -- checking reuse of search object. + local iter = assert (LD:search { base = BASE, scope = "base", }) + assert (type(iter) == "function") + local dn, e1 = iter() + assert (type(dn) == "string") + assert (type(e1) == "table") + dn, e1 = iter() + assert (type(dn) == "nil") + assert (type(e1) == "nil") + assert2 (false, pcall (iter)) + iter = nil + -- checking collecting search objects. + local dn, entry = LD:search { base = BASE, scope = "base" }() + collectgarbage() +end + + +--------------------------------------------------------------------- +-- checking rename operation. +--------------------------------------------------------------------- +function rename_test () + local _,_, rdn_name, rdn_value, parent_dn = string.find (NEW_DN, DN_PAT) + local new_rdn = rdn_name..'='..rdn_value..'_' + local new_dn = string.format ("%s,%s", new_rdn, parent_dn) + -- trying to rename with no parent. + check_future (true, LD.rename, LD, NEW_DN, new_rdn, nil) + -- trying to rename an invalid dn. + check_future (nil, LD.rename, LD, NEW_DN, new_rdn, nil) + -- trying to rename with the same parent. + check_future (true, LD.rename, LD, new_dn, rdn_name..'='..rdn_value, parent_dn) + -- trying to rename to an inexistent parent. + check_future (nil, LD.rename, LD, NEW_DN, new_rdn, new_dn) + -- mal-formed DN. + assert2 (false, pcall (LD.rename, LD, "")) + -- trying to rename with a closed connection. + assert2 (false, pcall (LD.rename, CLOSED_LD, NEW_DN, new_rdn, nil)) + -- trying to rename with an invalid connection. + assert2 (false, pcall (LD.rename, io.output(), NEW_DN, new_rdn, nil)) +end + + +--------------------------------------------------------------------- +-- checking delete operation. +--------------------------------------------------------------------- +function delete_test () + -- trying to delete with a closed connection. + assert2 (false, pcall (LD.delete, CLOSED_LD, NEW_DN)) + -- trying to delete with an invalid connection. + assert2 (false, pcall (LD.delete, io.output(), NEW_DN)) + -- trying to delete new entry. + check_future (true, LD.delete, LD, NEW_DN) + -- trying to delete an already deleted entry. + check_future (nil, LD.delete, LD, NEW_DN) + -- mal-formed DN. + check_future (nil, LD.delete, LD, "") + -- no DN. + assert2 (false, pcall (LD.delete, LD)) +end + + +--------------------------------------------------------------------- +-- checking close operation. +--------------------------------------------------------------------- +function close_test () + assert (LD:close () == 1, "couldn't close connection") +end + + +--------------------------------------------------------------------- +tests = { + { "basic checking", basic_test }, + { "checking compare operation", compare_test }, + { "checking basic search operation", search_test_1 }, + { "checking add operation", add_test }, + { "checking modify operation", modify_test }, + { "checking advanced search operation", search_test_2 }, + { "checking rename operation", rename_test }, + { "checking delete operation", delete_test }, + { "closing everything", close_test }, +} + +--------------------------------------------------------------------- +-- Main +--------------------------------------------------------------------- + +if table.getn(arg) < 1 then + print (string.format ("Usage %s host[:port] base [who [password]]", arg[0])) + os.exit() +end + +HOSTNAME = arg[1] +BASE = arg[2] +WHO = arg[3] +PASSWORD = arg[4] + +require"lualdap" +assert (type(lualdap)=="table", "couldn't load LDAP library") + +for i = 1, table.getn (tests) do + local t = tests[i] + io.write (t[1].." ...") + t[2] () + io.write (" OK !\n") +end |