# # # add_dir "tests/basic_invocation_and_options" # # add_dir "tests/importing_a_file" # # add_dir "tests/scanning_trees" # # add_file "tests/basic_invocation_and_options/__driver__.lua" # content [f1ffe6e2a14a8e4c212a3382714fe87986d3ac55] # # add_file "tests/importing_a_file/__driver__.lua" # content [2d945824ebdb4b72b0273d3df96f286e234029da] # # add_file "tests/min_hooks.lua" # content [d90ff30d41f1c9c73ea72ea50222370d07e1d575] # # add_file "tests/scanning_trees/__driver__.lua" # content [db3cde364e0388943bbc59ddb111c9a7b06abcf2] # # add_file "tests/scanning_trees/manifest" # content [aadf864f84c1a5cc529efbe890b510df5f491bea] # # add_file "tests/test_hooks.lua" # content [234fbb463da7e4614f0b0b279f21c658e74d3706] # # add_file "tests/test_keys" # content [68bfff4f90ab7f4b508170aa88997fc8d4dfbfa2] # # add_file "testsuite.lua" # content [1d440035999712d7b144f7b62327138977f16427] # # patch "tester.cc" # from [cee71a1f004e66cdd9447c23f1c16f9bfdb0c246] # to [f630973c81253bac1e2ddc79d7047fabf8e721dd] # # patch "tester.lua" # from [d2599eb84ec8f4a69baa547248fb39bb33f27c3b] # to [50ffae363ad71070d3a5f8dfd6b5305aa352e2f3] # # set "testsuite.lua" # attr "mtn:execute" # value "true" # ============================================================ --- tests/basic_invocation_and_options/__driver__.lua f1ffe6e2a14a8e4c212a3382714fe87986d3ac55 +++ tests/basic_invocation_and_options/__driver__.lua f1ffe6e2a14a8e4c212a3382714fe87986d3ac55 @@ -0,0 +1,14 @@ + +mtn_setup() + +check(prepare(raw_mtn("--norc")), 2, false) +check(prepare(raw_mtn("--help")), 2, false) +check(prepare(raw_mtn("--version")), 0, false) +check(prepare(raw_mtn("--nostd", "--help")), 2, false) +check(prepare(raw_mtn("--norc", "--help")), 2, false) +check(prepare(raw_mtn("--debug", "--help")), 2, false, false) +check(prepare(raw_mtn("--quiet", "--help")), 2, false) +check(prepare(raw_mtn("--db=foo.db", "--help")), 2, false) +check(prepare(raw_mtn("--db", "foo.db", "--help")), 2, false) +check(prepare(raw_mtn("address@hidden", "--help")), 2, false) +check(prepare(raw_mtn("--key", "address@hidden", "--help")), 2, false) ============================================================ --- tests/importing_a_file/__driver__.lua 2d945824ebdb4b72b0273d3df96f286e234029da +++ tests/importing_a_file/__driver__.lua 2d945824ebdb4b72b0273d3df96f286e234029da @@ -0,0 +1,13 @@ + +mtn_setup() + +writefile("importme", "version 0 of test file\n") + +check(prepare(sha1("importme")), 0, true) +tsha = string.gsub(readfile("stdout"), "%s*$", "") + +check(prepare(mtn("add", "importme")), 0, false, false) +check(prepare(commit()), 0, false, false) +check(prepare(mtn("automate", "get_file", tsha)), 0, true) +check(prepare(canonicalize("stdout"))) +check(prepare(cmp("importme", "stdout")), 0, false) ============================================================ --- tests/min_hooks.lua d90ff30d41f1c9c73ea72ea50222370d07e1d575 +++ tests/min_hooks.lua d90ff30d41f1c9c73ea72ea50222370d07e1d575 @@ -0,0 +1,7 @@ + +function get_passphrase(keyid) + return keyid +end +function persist_phrase_ok() + return true +end ============================================================ --- tests/scanning_trees/__driver__.lua db3cde364e0388943bbc59ddb111c9a7b06abcf2 +++ tests/scanning_trees/__driver__.lua db3cde364e0388943bbc59ddb111c9a7b06abcf2 @@ -0,0 +1,16 @@ + +mtn_setup() + +mkdir("foo") +mkdir("foo/bar") +writefile("testfile0", "version 0 of first test file\n") +writefile("foo/testfile1", "version 0 of second test file\n") +writefile("foo/bar/testfile2", "version 0 of third test file\n") +getfile("manifest") +check(prepare(canonicalize("manifest"))) + +check(prepare(mtn("add", "testfile0", "foo")), 0, false, false) +check(prepare(commit("testbranch")), 0, false, false) +check(prepare(mtn("automate", "get_manifest_of")), 0, true) +check(prepare(canonicalize("stdout"))) +check(prepare(cmp("stdout", "manifest")), 0, false) ============================================================ --- tests/scanning_trees/manifest aadf864f84c1a5cc529efbe890b510df5f491bea +++ tests/scanning_trees/manifest aadf864f84c1a5cc529efbe890b510df5f491bea @@ -0,0 +1,16 @@ +format_version "1" + +dir "" + +dir "foo" + +dir "foo/bar" + + file "foo/bar/testfile2" +content [85d521304e3660f05bbb458b05d0efc6e981f832] + + file "foo/testfile1" +content [14c5b672e2181377e41e6d8c5ce21457d8342667] + + file "testfile0" +content [5c39de9ca49b3aa34fa21f5778954665d947476c] ============================================================ --- tests/test_hooks.lua 234fbb463da7e4614f0b0b279f21c658e74d3706 +++ tests/test_hooks.lua 234fbb463da7e4614f0b0b279f21c658e74d3706 @@ -0,0 +1,71 @@ + +-- this is the "testing" set of lua hooks for monotone +-- it's intended to support self-tests, not for use in +-- production. just defines some of the std hooks. + +function get_passphrase(keyid) + return keyid +end + +-- Everything alice signs is trusted, nothing mallory signs is +-- trusted. For certs signed by other people, everything is +-- trusted except for one particular cert... +-- For use of t_trusted.at. +function get_revision_cert_trust(signers, id, name, val) + for k, v in pairs(signers) do + if v == "address@hidden" then return true end + if v == "address@hidden" then return false end + end + if (id == "0000000000000000000000000000000000000000" + and name == "bad-cert" and val == "bad-val") + then return false end + return true +end + +function get_manifest_cert_trust(signers, id, name, val) + return true +end + +function get_file_cert_trust(signers, id, name, val) + return true +end + +function accept_testresult_change(old_results, new_results) + for test,res in pairs(old_results) + do + if res == true and new_results[test] ~= true + then + return false + end + end + return true +end + +function persist_phrase_ok() + return true +end + +function get_author(branchname) + return "address@hidden" +end + +function ignore_file(name) + if (string.find(name, "testsuite.log")) then return true end + if (string.find(name, "test_hooks.lua")) then return true end + if (string.find(name, "keys")) then return true end + return false +end + +function merge2(left_path, right_path, merged_path, left, right) + io.write("running merge2 hook\n") + return left +end + +if (attr_functions == nil) then + attr_functions = {} +end +attr_functions["test:test_attr"] = + function(filename, value) + io.write(string.format("test:test_attr:%s:%s\n", filename, value)) + end + ============================================================ --- tests/test_keys 68bfff4f90ab7f4b508170aa88997fc8d4dfbfa2 +++ tests/test_keys 68bfff4f90ab7f4b508170aa88997fc8d4dfbfa2 @@ -0,0 +1,19 @@ +[keypair address@hidden +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6Pz+IvvOCDDqzN9WFO/zOjL7s9dVCS+zn +s/L9jQ2kHfNWXFof4GcgmMu4DfU4sUrRz39QxDlUrxEOvmIc9z3DNuIcbFZx7UZg9DWfdmDm +vbW79bZlVMeIudAIUwa6euX163AK5hacmqJfuB5U7awQM9o3rn8JYULleAoz5QTtawIDAQAB# +MIICyTBDBgkqhkiG9w0BBQ0wNjAeBgkqhkiG9w0BBQwwEQQIvYSV8ucj9m4CAggAAgEYMBQG +CCqGSIb3DQMHBAg/BZPM2O3QfASCAoBBGkVz4E/Pr1CsIioC92eCz4qWLclhc53HgHSCEo9I +XdNCTpCs/oxOXhQ0WQCPFhYEaxU8STgZm0Yhq8WEF1QfxOPOU8nDiwMT0L7/ARruu5bTCxnW +B3kkn+XiO5GldVJhULFlrl91t83yMsTSw+vyCyxZkqewBLR7mqHQUe2suVquMyutxxr2vZgV +QMfRxk65fSvySUHeNaj1dmakYcpP+35iejyUTAtAGuBsv2C68bwif4wkpLpedghNCtmccSdQ +t9QDF3yy6Q42tAW/OK6/t836/qn39f+47Kp4LMJUMmxNrtV7IntIkgBGgnGsqP9Br2B4GYXc +sWK0YApA3+Sf3kfH/wQ6Hib8nN4YxUTxxnS9WNHvRFrXCmfbGd5vAzi4lKCm/W+2Nlpd4DDQ +3JZjjCR73PMfKtHJCGULkNkK/9kRyhLYql2u/ZUJoEcdZxzEpYgExW8Wu1CrCVtWd+ueXs1h +or6Fdua7Gg4cjMgVg6EUSxdMBFQCX8heD8JeG6jMFNR9hTxe8o/PK8Ys63JyLMLRUv3Ud+f8 +8T0TtCZV5+rgLfvb6k89uDJJK228WuJB6rp8S+qqq30RFPmkzW8JNulRilY+wrIfcowA6+TA +T5WKzFOIbkZd/R34tNLJMjTJlUq6SQKaOlQnqOEFbyY/GXgzYgnmc3tl8pigXEJvNzU5GiuB +ib35QQbzh87KlfLtWELK+8ZoyhZAZAMr97IavUbuFubOyEoEozUliARyRZ1ZudM4Ii+J6TRX +cmLryIBlz3OXgUUBSwJPwtWuR4tZ8nIt7cVJr7pxLblGfeFuu01HWN55hv4C78/aNSipVYCF +OFt8n7wQHxbbJvoTIdd/ +[end] ============================================================ --- testsuite.lua 1d440035999712d7b144f7b62327138977f16427 +++ testsuite.lua 1d440035999712d7b144f7b62327138977f16427 @@ -0,0 +1,75 @@ +#!./tester + +function safe_mtn(...) + return "mtn", "--norc", "--root=" .. test_root, unpack(arg) +end + +-- function preexecute(...) +-- return "valgrind", "--tool=memcheck", unpack(arg) +-- end + +function raw_mtn(...) + if preexecute ~= nil then + return preexecute(safe_mtn(unpack(arg))) + else + return safe_mtn(unpack(arg)) + end +end + +function mtn(...) + return raw_mtn("--rcfile", test_root .. "/test_hooks.lua", + "--nostd", "--db=" .. test_root .. "/test.db", + "--keydir", test_root .. "/keys", + "address@hidden", unpack(arg)) +end + +function commit(branch) + if branch == nil then branch = "testbranch" end + return mtn("commit", "--message=blah-blah", "--branch", branch) +end + +function sha1(what) + return safe_mtn("identify", what) +end + +function mtn_setup() + getstdfile("tests/test_keys", "test_keys") + getstdfile("tests/test_hooks.lua", "test_hooks.lua") + getstdfile("tests/min_hooks.lua", "min_hooks.lua") + port = math.random(20000, 50000) + + check(prepare(mtn("db", "init")), 0, false, false) + check(prepare(mtn("read", "test_keys")), 0, false, false) + check(prepare(mtn("setup", "--branch=testbranch", ".")), 0, false, false) + os.remove("test_keys") +end + +function canonicalize(filename) + local func = function (fn) + local f = io.open(filename, "rb") + local indat = f:read("*a") + f:close() + local outdat = string.gsub(indat, "\r\n", "\n") + f = io.open(filename, "wb") + f:write(outdat) + f:close() + return 0 + end + local nullfunc = function (fn) return 0 end + local ostype = os.getenv("OSTYPE") + local osenv = os.getenv("OS") + if osenv ~= nil then osenv = string.find(osenv, "[Ww]in") end + if ostype == "msys" or osenv then + return func, filename + else + return nullfunc, filename + end +end + +------------------------------------------------------------------------ +--====================================================================-- +------------------------------------------------------------------------ + +table.insert(tests, "tests/basic_invocation_and_options") +table.insert(tests, "tests/scanning_trees") +table.insert(tests, "tests/importing_a_file") ============================================================ --- tester.cc cee71a1f004e66cdd9447c23f1c16f9bfdb0c246 +++ tester.cc f630973c81253bac1e2ddc79d7047fabf8e721dd @@ -19,6 +19,33 @@ using std::string; using boost::lexical_cast; + +#ifdef WIN32 +#include +inline int dup2(int x, int y) {return _dup2(x,y);} +inline int dup(int x) {return _dup(x);} +inline int close(int x) {return _close(x);} +#else +#include +#endif + +int set_redirect(int what, string where, string mode) +{ + int saved = dup(what); + FILE *f = fopen(where.c_str(), mode.c_str()); + if (!f) + return -1; + dup2(fileno(f), what); + fclose(f); + return saved; +} +void clear_redirect(int what, int saved) +{ + dup2(saved, what); + close(saved); +} + + fs::path source_dir; fs::path run_dir; @@ -37,20 +64,49 @@ char const * testname = luaL_checkstring(L, -1); fs::path tname(testname, fs::native); fs::path testdir = run_dir / tname.leaf(); + if (fs::exists(testdir)) + fs::remove_all(testdir); fs::create_directory(testdir); go_to_workspace(testdir.native_file_string()); lua_pushstring(L, testdir.native_file_string().c_str()); - return 1; + lua_pushstring(L, tname.leaf().c_str()); + return 2; } static int + clean_test_dir(lua_State *L) + { + char const * testname = luaL_checkstring(L, -1); + fs::path tname(testname, fs::native); + fs::path testdir = run_dir / tname.leaf(); + go_to_workspace(run_dir.native_file_string()); + fs::remove_all(testdir); + return 0; + } + + static int + leave_test_dir(lua_State *L) + { + go_to_workspace(run_dir.native_file_string()); + return 0; + } + + static int + make_dir(lua_State *L) + { + char const * dirname = luaL_checkstring(L, -1); + fs::path dir(dirname, fs::native); + fs::create_directory(dir); + return 0; + } + + static int get_source_dir(lua_State * L) { lua_pushstring(L, source_dir.native_file_string().c_str()); return 1; } - /* static int set_redirect(lua_State * L) { @@ -58,6 +114,10 @@ char const * outfile = luaL_checkstring(L, -2); char const * errfile = luaL_checkstring(L, -1); + int infd = set_redirect(0, infile, "r"); + int outfd = set_redirect(1, outfile, "w"); + int errfd = set_redirect(2, errfile, "w"); + lua_pushnumber(L, infd); lua_pushnumber(L, outfd); lua_pushnumber(L, errfd); @@ -70,9 +130,13 @@ int infd = luaL_checknumber(L, -3); int outfd = luaL_checknumber(L, -2); int errfd = luaL_checknumber(L, -1); + + clear_redirect(0, infd); + clear_redirect(1, outfd); + clear_redirect(2, errfd); + return 0; } - */ } int main(int argc, char **argv) @@ -81,11 +145,12 @@ if (argc > 1) { fs::path file(argv[1], fs::native); - testfile = argv[1]; + testfile = fs::complete(file).native_file_string(); save_initial_path(); source_dir = fs::complete(file.branch_path()); run_dir = fs::initial_path() / "tester_dir"; fs::create_directory(run_dir); + go_to_workspace(run_dir.native_file_string()); } else { @@ -103,8 +168,11 @@ add_functions(st); lua_register(st, "go_to_test_dir", go_to_test_dir); lua_register(st, "get_source_dir", get_source_dir); -// lua_register(st, "set_redirect", set_redirect); -// lua_register(st, "clear_redirect", clear_redirect); + lua_register(st, "set_redirect", set_redirect); + lua_register(st, "clear_redirect", clear_redirect); + lua_register(st, "clean_test_dir", go_to_test_dir); + lua_register(st, "leave_test_dir", leave_test_dir); + lua_register(st, "mkdir", make_dir); int ret = 2; try ============================================================ --- tester.lua d2599eb84ec8f4a69baa547248fb39bb33f27c3b +++ tester.lua 50ffae363ad71070d3a5f8dfd6b5305aa352e2f3 @@ -1,11 +1,46 @@ tests = {} srcdir = get_source_dir() test_root = nil testname = nil -function getfile(name) - local infile = io.open(srcdir .. "/" .. testname .. "/" .. name, "rb") - local outfile = io.open(name, "wb") +logfile = io.open("tester.log", "w") -- combined logfile +test_log = nil -- logfile for this test +failed_testlogs = {} + +function fsize(filename) + local file = io.open(filename, "r") + if file == nil then error("Cannot open file " .. filename, 2) end + local size = file:seek("end") + file:close() + return size +end + +function readfile(filename) + local file = io.open(filename, "rb") + if file == nil then error("Cannot open file " .. filename, 2) end + local dat = file:read("*a") + file:close() + return dat +end + +function writefile(filename, dat) + local file = io.open(filename, "wb") + if file == nil then error("Cannot open file " .. filename, 2) end + file:write(dat) + file:close() + return +end + +function getstdfile(name, as) + local infile = io.open(srcdir .. "/" .. name, "rb") + if infile == nil then + error("Cannot open file " .. srcdir .. "/" .. name, 2) + end + local outfile = io.open(as, "wb") + if outfile == nil then + infile:close() + error("Cannot open file " .. as, 2) + end local size = 2^13 while true do local block = infile:read(size) @@ -16,6 +51,11 @@ outfile:close() end +function getfile(name, as) + if as == nil then as = name end + getstdfile(testname .. "/" .. name, as) +end + function execute(path, ...) local pid local ret = -1 @@ -24,37 +64,151 @@ return ret end -function prepare(...) - return function () return execute(unpack(arg)) end +function prepare(first, ...) + if type(first) == "string" then + test_log:write("\n", first, " ", table.concat(arg, " "), "\n") + return function () return execute(first, unpack(arg)) end + elseif type(first) == "function" then + test_log:write("\n ", table.concat(arg, " "), "\n") + return function () return first(unpack(arg)) end + else + error("prepare() called with argument of unknown type " .. type(first), 2) + end end +function cmp(left, right) + local docmp = function (left, right) + local ldat = nil + local rdat = nil + if left == "-" then + ldat = io.input:read("*a") + rdat = readfile(right) + elseif right == "-" then + rdat = io.input:read("*a") + ldat = readfile(left) + else + if fsize(left) ~= fsize(right) then + return 1 + else + ldat = readfile(left) + rdat = readfile(right) + end + end + if ldat == rdat then return 0 else return 1 end + end + return docmp, left, right +end + +-- std{out,err} can be: +-- * false: ignore +-- * true: ignore, copy to stdout +-- * string: check that it matches the contents +-- * nil: must be empty function check(func, ret, stdout, stderr, stdin) if ret == nil then ret = 0 end - -- local i, o, e = set_redirect("stdin", "stdout", "stderr") - local result = func() - -- clear_redirect(i, o, e) + if stdin ~= true then + local infile = io.open("stdin", "w") + if stdin ~= nil and stdin ~= false then + infile:write(stdin) + end + infile:close() + end + os.remove("ts-stdin") + os.rename("stdin", "ts-stdin") + local i, o, e = set_redirect("ts-stdin", "ts-stdout", "ts-stderr") + local ok, result = pcall(func) + clear_redirect(i, o, e) + if ok == false then + error(result, 2) + end if result ~= ret then - error("Check failed: wanted " .. ret .. " got " .. result, 2) + error("Check failed (return value): wanted " .. ret .. " got " .. result, 2) end + + if stdout == nil then + if fsize("ts-stdout") ~= 0 then + error("Check failed (stdout): not empty", 2) + end + elseif type(stdout) == "string" then + local realout = io.open("stdout") + local contents = realout:read("*a") + realout:close() + if contents ~= stdout then + error("Check failed (stdout): doesn't match", 2) + end + elseif stdout == true then + os.remove("stdout") + os.rename("ts-stdout", "stdout") + end + + if stderr == nil then + if fsize("ts-stderr") ~= 0 then + error("Check failed (stderr): not empty", 2) + end + elseif type(stderr) == "string" then + local realerr = io.open("stderr") + local contents = realerr:read("*a") + realerr:close() + if contents ~= stderr then + error("Check failed (stderr): doesn't match", 2) + end + elseif stderr == true then + os.remove("stderr") + os.rename("ts-stderr", "stderr") + end end +function P(...) + io.write(unpack(arg)) + io.flush() + logfile:write(unpack(arg)) +end + function run_tests(args) print("Args:") for i,a in pairs(args) do print ("\t", i, a) end - print("Running tests...") + P("Running tests...\n") + local failed = 0 for i,t in pairs(tests) do testname = t - io.write(i .. "\t" .. testname .. "\t") - test_root = go_to_test_dir(testname) + local shortname = nil + test_root, shortname = go_to_test_dir(t) + if i < 100 then P(" ") end + if i < 10 then P(" ") end + P(i .. " " .. shortname) + local spacelen = 60 - string.len(shortname) + local spaces = string.rep(" ", 7) + if spacelen > 0 then P(string.sub(spaces, 1, spacelen)) end + + local tlog = test_root .. "/tester.log" + test_log = io.open(tlog, "w") + test_log:write("Test number ", i, ", ", shortname, "\n") + local driver = srcdir .. "/" .. testname .. "/__driver__.lua" local r,e = xpcall(loadfile(driver), debug.traceback) if r then - io.write("OK.\n") + P("ok\n") + clean_test_dir(testname) else - io.write("Test failed: " .. e .. "\n") + P("FAIL\n") + test_log:write("\n", e, "\n") + failed = failed + 1 + table.insert(failed_testlogs, tlog) + leave_test_dir() end + test_log:close() end - return 0 + + for i,log in pairs(failed_testlogs) do + local tlog = io.open(log, "r") + if tlog ~= nil then + local dat = tlog:read("*a") + tlog:close() + logfile:write(dat) + end + end + + if failed == 0 then return 0 else return 1 end end