# # # add_dir "tests/(normal)_netsync_on_partially_unrelated_revisions" # # add_dir "tests/disapproving_of_a_revision" # # add_dir "tests/exchanging_work_via_netsync" # # add_dir "tests/netsync_transfers_public_keys" # # add_dir "tests/repeatedly_exchanging_work_via_netsync" # # add_dir "tests/single_manifest_netsync" # # add_file "tests/(normal)_netsync_on_partially_unrelated_revisions/__driver__.lua" # content [1581e71b144754fbec637bcd212c8c424dcfa1b7] # # add_file "tests/disapproving_of_a_revision/__driver__.lua" # content [b30c89146ff365d9a5c73927e82119fa27d6521d] # # add_file "tests/disapproving_of_a_revision/badfile" # content [edb043f48a2b91914e3d7f0d443f09405388f42f] # # add_file "tests/disapproving_of_a_revision/finalfile" # content [37492211554020fc4264f6e1b786ae3159d14bb4] # # add_file "tests/disapproving_of_a_revision/goodfile" # content [1901cbc55ee28e0b3f57d358d4c260dbd92d95e9] # # add_file "tests/disapproving_of_a_revision/rootfile" # content [aa28e376c2dfb3908bfc5fe1f502a7af4cb81d40] # # add_file "tests/disapproving_of_a_revision/updatefile" # content [cc97f4c30e83293c486e2765904d59a287875888] # # add_file "tests/exchanging_work_via_netsync/__driver__.lua" # content [f6c1718742a80d452437f19101dcc41ba9574479] # # add_file "tests/netsync.lua" # content [ac4d58f0fe321f1873f737156b28a42e54746581] # # add_file "tests/netsync_transfers_public_keys/__driver__.lua" # content [c722036c34b5f223c1ab9ce1972067f15b848930] # # add_file "tests/netsync_transfers_public_keys/newkeys.txt" # content [6c7a73575c67b139ec6284ce8c53009bdf4de951] # # add_file "tests/netsync_with_notes.lua" # content [9ac0fce9c0c5646239c38b438f625ffca1473877] # # add_file "tests/repeatedly_exchanging_work_via_netsync/__driver__.lua" # content [22d7b50f5a96ed4c3813f26293821d2a9feb3aad] # # add_file "tests/single_manifest_netsync/__driver__.lua" # content [1a5b0b9698c3b6b2a1f40405475ce06e307a7a8e] # # patch "platform.hh" # from [c13733dd285d20b7e0284f127afbfb332bbbd00f] # to [0fe8d1de83309dc15f222d9173b13510bd237655] # # patch "tester.cc" # from [c8d27ba5780504cfe3c4e6dc70096daf7cdc269a] # to [a25b181d8d90f25ddb019673decde4ab01eb921f] # # patch "tester.lua" # from [e6ccae74a62bb918e905e87d141d787e804166a7] # to [2652b5718374679f2026bc9d8e85051e88018931] # # patch "testsuite.at" # from [33beef0685a0c8139f659e4fc69d5b46b0e77a0c] # to [0061fcad7d9c8da8ed4519e26dd2d1935ab0eccc] # # patch "testsuite.lua" # from [354a2946c7548b447bda504e476be5666567d54e] # to [8a7a8643419cbeb1bffacb3c2b00bd28f5e4febf] # # patch "unix/process.cc" # from [93c62c374ed212a5612d02dfe5d22eeecdd6456c] # to [04fb1d79c00ec3dddb30fab643b71bef0006cb13] # # patch "win32/process.cc" # from [615b38daf893dd7dd4fc7856ba36684795462efc] # to [cd470989510d05f0a9e619b880183df66b5df6f3] # ============================================================ --- tests/(normal)_netsync_on_partially_unrelated_revisions/__driver__.lua 1581e71b144754fbec637bcd212c8c424dcfa1b7 +++ tests/(normal)_netsync_on_partially_unrelated_revisions/__driver__.lua 1581e71b144754fbec637bcd212c8c424dcfa1b7 @@ -0,0 +1,49 @@ + +mtn_setup() + +-- This test relies on file-suturing + +-- This tests netsync'ing +-- +-- A B +-- \ / +-- C +-- +-- where A starts out shared, but B and C do not. + +-- For analysis and discussion of solutions, see: +-- http://lists.gnu.org/archive/html/monotone-devel/2004-11/msg00043.html +-- There are other strategies that might be good besides the one +-- mentioned there; doing sideways deltas between heads, all sorts of +-- possibilities for maybe-efficient algorithms. + +netsync_setup() + +addfile("testfile1", "This is test file 1") +commit("testbranch") +base = base_revision() + +run_netsync("pull", "testbranch") + +for _,i in pairs{{"automate", "graph"}, {"ls", "certs", base}} do + check_same_stdout(cmd(mtn(unpack(i))), cmd(mtn2(unpack(i)))) +end + +remove_recursive("_MTN") +check(cmd(mtn("setup", "--branch=testbranch", ".")), 0, false, false) + +addfile("testfile2", "This is test file 2") +commit("testbranch") +unrelated = base_revision() + +xfail_if(true, cmd(mtn("--branch=testbranch", "merge")), 0, false, false) +check(cmd(mtn("update")), 0, false, false) +merge = base_revision() + +run_netsync("pull", "testbranch") + +check_same_stdout(cmd(mtn("automate", "graph")), cmd(mtn2("automate", "graph"))) +for _,i in pairs{base, unrelated, merge} do + check_same_stdout(cmd(mtn("ls", "certs", i)), + cmd(mtn2("ls", "certs", i))) +end ============================================================ --- tests/disapproving_of_a_revision/__driver__.lua b30c89146ff365d9a5c73927e82119fa27d6521d +++ tests/disapproving_of_a_revision/__driver__.lua b30c89146ff365d9a5c73927e82119fa27d6521d @@ -0,0 +1,33 @@ + +mtn_setup() + +getfile("rootfile", "testfile") +check(cmd(mtn("add", "testfile")), 0, false, false) +commit() +root_r_sha = base_revision() +root_f_sha = sha1("testfile") + +getfile("goodfile", "testfile") +commit() +left_good_r_sha = base_revision() +left_good_f_sha = sha1("testfile") +check(left_good_r_sha ~= root_r_sha) +check(left_good_f_sha ~= root_f_sha) + +getfile("badfile", "testfile") +commit() +left_bad_r_sha = base_revision() +left_bad_f_sha = sha1("testfile") +check(left_bad_r_sha ~= left_good_r_sha) +check(left_bad_f_sha ~= left_good_f_sha) + +probe_node("testfile", root_r_sha, root_f_sha) + +getfile("updatefile", "testfile") +check(cmd(mtn("disapprove", left_bad_r_sha)), 0, false, false) +check(cmd(mtn("update")), 0, false, false) + +-- files should now be merged + +getfile("finalfile", "probe") +check(samefile("testfile", "probe")) ============================================================ --- tests/disapproving_of_a_revision/badfile edb043f48a2b91914e3d7f0d443f09405388f42f +++ tests/disapproving_of_a_revision/badfile edb043f48a2b91914e3d7f0d443f09405388f42f @@ -0,0 +1,5 @@ +first line of the file +an insertion between first and second +second line of the file +third line of the file +an evil line which should never be seen ============================================================ --- tests/disapproving_of_a_revision/finalfile 37492211554020fc4264f6e1b786ae3159d14bb4 +++ tests/disapproving_of_a_revision/finalfile 37492211554020fc4264f6e1b786ae3159d14bb4 @@ -0,0 +1,5 @@ +first line of the file +an insertion between first and second +second line of the file +an insertion between second and third +third line of the file ============================================================ --- tests/disapproving_of_a_revision/goodfile 1901cbc55ee28e0b3f57d358d4c260dbd92d95e9 +++ tests/disapproving_of_a_revision/goodfile 1901cbc55ee28e0b3f57d358d4c260dbd92d95e9 @@ -0,0 +1,4 @@ +first line of the file +an insertion between first and second +second line of the file +third line of the file ============================================================ --- tests/disapproving_of_a_revision/rootfile aa28e376c2dfb3908bfc5fe1f502a7af4cb81d40 +++ tests/disapproving_of_a_revision/rootfile aa28e376c2dfb3908bfc5fe1f502a7af4cb81d40 @@ -0,0 +1,3 @@ +first line of the file +second line of the file +third line of the file ============================================================ --- tests/disapproving_of_a_revision/updatefile cc97f4c30e83293c486e2765904d59a287875888 +++ tests/disapproving_of_a_revision/updatefile cc97f4c30e83293c486e2765904d59a287875888 @@ -0,0 +1,4 @@ +first line of the file +second line of the file +an insertion between second and third +third line of the file ============================================================ --- tests/exchanging_work_via_netsync/__driver__.lua f6c1718742a80d452437f19101dcc41ba9574479 +++ tests/exchanging_work_via_netsync/__driver__.lua f6c1718742a80d452437f19101dcc41ba9574479 @@ -0,0 +1,52 @@ + +mtn_setup() +netsync_setup() + +writefile("testfile", "version 0 of test file") +check(cmd(mtn("add", "testfile")), 0, false, false) +commit() +f_ver = {} +ver = {} +f_ver[0] = sha1("testfile") +ver[0] = base_revision() + +writefile("testfile", "version 1 of test file") +commit() +f_ver[1] = sha1("testfile") +ver[1] = base_revision() + +run_netsync("pull", "testbranch") + +check(cmd(mtn2("ls", "certs", ver[0])), 0, true) +rename("stdout", "certs") +check(qgrep("date", "certs")) +check(qgrep("author", "certs")) +check(qgrep("branch", "certs")) +check(qgrep("changelog", "certs")) +check(not qgrep("bad", "certs")) + +check(cmd(mtn2("ls", "certs", ver[1])), 0, true) +rename_over("stdout", "certs") +check(qgrep("date", "certs")) +check(qgrep("author", "certs")) +check(qgrep("branch", "certs")) +check(qgrep("changelog", "certs")) +check(not qgrep("bad", "certs")) + +for _, what in {{cmd = "get_revision", ver = ver[0]}, + {cmd = "get_revision", ver = ver[1]}, + {cmd = "get_file", ver = f_ver[0]}, + {cmd = "get_file", ver = f_ver[1]}} do + check(cmd(mtn2("automate", what.cmd, what.ver)), 0, true) + canonicalize("stdout") + check(sha1("stdout") == what.ver) +end + +check(cmd(mtn("db", "info")), 0, true) +canonicalize("stdout") +info1 = sha1("stdout") +check(cmd(mtn2("db", "info")), 0, true) +canonicalize("stdout") +info2 = sha1("stdout") +check(info1 == info2) + ============================================================ --- tests/netsync.lua ac4d58f0fe321f1873f737156b28a42e54746581 +++ tests/netsync.lua ac4d58f0fe321f1873f737156b28a42e54746581 @@ -0,0 +1,7 @@ +function get_netsync_read_permitted(pattern, identity) + return true +end + +function get_netsync_write_permitted(identity) + return true +end ============================================================ --- tests/netsync_transfers_public_keys/__driver__.lua c722036c34b5f223c1ab9ce1972067f15b848930 +++ tests/netsync_transfers_public_keys/__driver__.lua c722036c34b5f223c1ab9ce1972067f15b848930 @@ -0,0 +1,40 @@ + +mtn_setup() +netsync_setup() + +pubkey = "52f32ec62128ea3541ebdd9d17400e268cfcd3fe" +privkey = "06b040c37796863b53f10dc23fcccf379cc2e259" + +getfile("newkeys.txt", "stdin") +check(cmd(mtn("read")), 0, false, false, true) + +-- First commit a version that doesn't use the new key, and make sure +-- that it doesn't get transferred. +addfile("testfile", "version 0 of test file") +commit("testbranch") + +run_netsync("pull", "testbranch") + +check(cmd(mtn2("ls", "keys")), 0, true, false) +check(not qgrep(pubkey, "stdout")) +check(not qgrep(privkey, "stdout")) + +-- Now check that --key-to-push works. +srv = netsync_serve_start("testbranch", 2) +check(cmd(mtn("--rcfile=netsync.lua", "push", netsync_address, + "testbranch", "address@hidden")), + 0, false, false) +srv:finish() +check(cmd(mtn2("dropkey", "address@hidden")), 0, false, false) + +-- Now commit a version that does use the new key, and make sure that +-- now it does get transferred. +writefile("testfile", "version 1 of test file") +check(cmd(mtn("--branch=testbranch", "--message=blah-blah", + "address@hidden", "commit")), 0, false, false) + +run_netsync("pull", "testbranch") + +check(cmd(mtn2("ls", "keys")), 0, true, false) +check(qgrep(pubkey, "stdout")) +check(not qgrep(privkey, "stdout")) ============================================================ --- tests/netsync_transfers_public_keys/newkeys.txt 6c7a73575c67b139ec6284ce8c53009bdf4de951 +++ tests/netsync_transfers_public_keys/newkeys.txt 6c7a73575c67b139ec6284ce8c53009bdf4de951 @@ -0,0 +1,19 @@ +[keypair address@hidden +MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC+6X7+HI715//0pWHWGcN/tw439uUUahtD +wV8ckNKFTCKnWU0U4mzanMoKJCeSRttR7uRkmWPQX3e9pq8Klcpocws1/XpJr31NhDqvWmTb +ABduS/GJeSZugrU6MYBLX12eLUCynWXoSXRGtX+9Xrjt2pAMAq3LkSDcRUUgYOCS+wIBEQ==# +MIICwTBDBgkqhkiG9w0BBQ0wNjAeBgkqhkiG9w0BBQwwEQQIyZNAO/PyGHECAggAAgEYMBQG +CCqGSIb3DQMHBAhy4+o+3DMQTQSCAnhpZiO9ILoVB8+Hw4FsbckY1rIE7UnDLJqxVJO0+Ghg +rBKtLqMH/mfakbkPVCACYte/wxC1a4lsuf6oEIMryW93V5RplIVIPgFpzLT7zj1ih1YXAh0X +aSMdDbtAgAVTppRTZfgQPJ8nJ+tD7Y4ckVAbbyv5Sbr1is5qzv4bqiwvpL2heNcbiaHOyxzO +Df93tlK36o9Qd2uoGXZ+uaZs5LrFe8xZuuV1++iSWMnClIMICS67i7tCha5juwcCAouy8oyg +jLGsQhwTfAwLHCC0TvZeHTG6EM+jkqAKDvL6ud+5gN6f0HFIV9DPUJSJ01vaqFBWWFQ28ilz +0l6fINeac2E/UBYRrJUY5tQ6fKEurPcDWNynsVFDKv/CG0ePZko9b715cYdfLwCIiBm+4z9/ +bpGc6zy2RfZqYk9Ui8hviaI9UShZWB3iglKq3NRVwBY0xX6HysYp2T+Lb5cHb9lCPP1INPfx +VdgMlYMcd+3HmAdEF05K6UkqECc7ZIvz7KrWXEvDoBV1cVQZ5QvoDOvQFMCKjvetnIpE7wCO +HxhHt6FiCVLJyvvOhystmJtuzg1/R1SIE00XEXgLLQS2We1wuZesjwB7u10NYArl1zqD/XJb +/q1EM4YFSXnvCL0KitZ244NP3CteSydVChYTgHkSDRnaZ2sx3tTLJLaekYCRUFKKs+xF750f +nVBgfV13p+heGn94EcJfVJVszAYiTKolmtgkqXij0mInJGxwRAEQq4La1va9WwNHndK2R8vj ++nAB7jJFgpAwiotl7g+7LW65ZR6Z2lLZhIJG7HlOwlDFq6oAjgWOZFu2s+dqu9MgMF2C9d3d ++rhboyouJg== +[end] ============================================================ --- tests/netsync_with_notes.lua 9ac0fce9c0c5646239c38b438f625ffca1473877 +++ tests/netsync_with_notes.lua 9ac0fce9c0c5646239c38b438f625ffca1473877 @@ -0,0 +1,41 @@ +logfile = nil + +function note_netsync_start() + logfile = io.open("testnotes.log","w") + logfile:write("start ---------------------------------------------------\n") +end + +function note_netsync_revision_received(new_id, revision, certs) + logfile:write("revision: new_id = " .. new_id .. "\n") + logfile:write("revision: revision = " .. revision .. "\n") + for i, cert in pairs(certs) + do + logfile:write("revision: cert.name = " .. cert.name .. "\n") + logfile:write("revision: cert.value = " .. cert.value .. "\n") + logfile:write("revision: cert.key = " .. cert.key .. "\n") + end +end + +function note_netsync_cert_received(rev_id, key, name, value) + logfile:write("cert: rev_id = " .. rev_id .. "\n") + logfile:write("cert: name = " .. name .. "\n") + logfile:write("cert: value = " .. value .. "\n") + logfile:write("cert: key = " .. key .. "\n") +end + +function note_netsync_pubkey_received(keyname) + logfile:write("pubkey: " .. keyname .. "\n") +end + +function note_netsync_end() + logfile:write("end -----------------------------------------------------\n") + logfile:close() +end + +function get_netsync_read_permitted(pattern, identity) + return true +end + +function get_netsync_write_permitted(identity) + return true +end ============================================================ --- tests/repeatedly_exchanging_work_via_netsync/__driver__.lua 22d7b50f5a96ed4c3813f26293821d2a9feb3aad +++ tests/repeatedly_exchanging_work_via_netsync/__driver__.lua 22d7b50f5a96ed4c3813f26293821d2a9feb3aad @@ -0,0 +1,33 @@ + +mtn_setup() +netsync_setup() + +addfile("testfile", "version 0 data") +commit("testbranch") +ver = {} +ver[0] = base_revision() + +run_netsync("pull", "testbranch") + +addfile("testfile2", "some data") +commit("testbranch") +ver[1] = base_revision() + +revert_to(ver[0]) + +writefile("testfile", "version 1 data") +commit("testbranch") +ver[2] = base_revision() + +check(cmd(mtn("--branch=testbranch", "merge")), 0, false, false) +check(cmd(mtn("update")), 0, false, false) +ver[3] = base_revision() + +run_netsync("pull", "testbranch") + +check_same_stdout(cmd(mtn("automate", "graph")), cmd(mtn2("automate", "graph"))) + +for i = 1,3 do + check_same_stdout(cmd(mtn("ls", "certs", ver[i])), + cmd(mtn2("ls", "certs", ver[i]))) +end ============================================================ --- tests/single_manifest_netsync/__driver__.lua 1a5b0b9698c3b6b2a1f40405475ce06e307a7a8e +++ tests/single_manifest_netsync/__driver__.lua 1a5b0b9698c3b6b2a1f40405475ce06e307a7a8e @@ -0,0 +1,33 @@ + +mtn_setup() +netsync_setup() + +writefile("testfile", "version 0 of test file") +check(cmd(mtn("add", "testfile")), 0, false, false) +commit("testbranch") +f_ver = sha1("testfile") +ver = base_revision() + +run_netsync("pull", "testbranch") + +check(cmd(mtn2("ls", "certs", ver)), 0, true) +rename("stdout", "certs") +check(qgrep("date", "certs")) +check(qgrep("author", "certs")) +check(qgrep("branch", "certs")) +check(qgrep("changelog", "certs")) +check(not qgrep("bad", "certs")) + +check(cmd(mtn2("automate", "get_revision", ver)), 0, true) +canonicalize("stdout") +check(sha1("stdout") == ver) + +check(cmd(mtn2("automate", "get_file", f_ver)), 0, true) +canonicalize("stdout") +check(sha1("stdout") == f_ver) + +check(cmd(mtn("db", "info")), 0, true) +info1 = sha1("stdout") +check(cmd(mtn2("db", "info")), 0, true) +info2 = sha1("stdout") +check(info1 == info2) ============================================================ --- platform.hh c13733dd285d20b7e0284f127afbfb332bbbd00f +++ platform.hh 0fe8d1de83309dc15f222d9173b13510bd237655 @@ -24,7 +24,7 @@ int existsonpath(const char *exe); int make_executable(const char *path); pid_t process_spawn(const char * const argv[]); -int process_wait(pid_t pid, int *res); +int process_wait(pid_t pid, int *res, int timeout = -1);// default infinite int process_kill(pid_t pid, int signal); int process_sleep(unsigned int seconds); ============================================================ --- tester.cc c8d27ba5780504cfe3c4e6dc70096daf7cdc269a +++ tester.cc a25b181d8d90f25ddb019673decde4ab01eb921f @@ -9,6 +9,7 @@ #include "tester.h" #include "paths.hh" #include "platform.hh" +#include "sanity.hh" #include @@ -212,17 +213,25 @@ fs::path source_dir; fs::path run_dir; -struct oops : public std::exception +static int panic_thrower(lua_State * st) { - oops(string const &s = "") throw() : err(s) {} - ~oops() throw() {} - string err; - char const * what() {return err.c_str();} -}; + throw oops("lua error"); +} -static int panic_thrower(lua_State * st) +void copy_recursive(fs::path const &from, fs::path const &to) { - throw oops(); + if (!fs::exists(from)) + return; + if (fs::exists(to)) + fs::remove_all(to); + if (fs::is_directory(from)) + { + fs::create_directory(to); + for (fs::directory_iterator i(from); i != fs::directory_iterator(); ++i) + copy_recursive(*i, to / i->leaf()); + } + else + fs::copy_file(from, to); } extern "C" @@ -256,13 +265,21 @@ static int remove_recursive(lua_State *L) { - char const * dirname = luaL_checkstring(L, -1); - fs::path dir(dirname, fs::native); + fs::path dir(luaL_checkstring(L, -1)); fs::remove_all(dir); return 0; } static int + copy_recursive(lua_State *L) + { + fs::path from(luaL_checkstring(L, -2)); + fs::path to(luaL_checkstring(L, -1)); + copy_recursive(from, to); + return 0; + } + + static int leave_test_dir(lua_State *L) { go_to_workspace(run_dir.native_file_string()); @@ -318,6 +335,10 @@ sb->out = set_redirect(redirect::out, outfile); sb->err = set_redirect(redirect::err, errfile); lua_newtable(L); + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + lua_pushstring(L, "restore"); lua_pushcfunction(L,clear_redirect); lua_settable(L, -3); @@ -357,10 +378,24 @@ set_env(var, val); return 0; } + + static int + timed_wait(lua_State * L) + { + pid_t pid = luaL_checknumber(L, -2); + int time = luaL_checknumber(L, -1); + int res; + int ret; + ret = process_wait(pid, &res, time); + lua_pushnumber(L, res); + lua_pushnumber(L, ret); + return 2; + } } int main(int argc, char **argv) { +// global_sanity.set_debug(); string testfile; bool needhelp = false; for (int i = 1; i < argc; ++i) @@ -405,11 +440,13 @@ lua_register(st, "leave_test_dir", leave_test_dir); lua_register(st, "mkdir", make_dir); lua_register(st, "remove_recursive", remove_recursive); + lua_register(st, "copy_recursive", copy_recursive); lua_register(st, "exists", exists); lua_register(st, "get_ostype", get_ostype); lua_register(st, "save_env", do_save_env); lua_register(st, "restore_env", do_restore_env); lua_register(st, "set_env", do_set_env); + lua_register(st, "timed_wait", timed_wait); int ret = 2; try ============================================================ --- tester.lua e6ccae74a62bb918e905e87d141d787e804166a7 +++ tester.lua 2652b5718374679f2026bc9d8e85051e88018931 @@ -11,6 +11,8 @@ logfile = io.open("tester.log", "w") -- combined logfile test_log = nil -- logfile for this test failed_testlogs = {} +bgid = 0 +bglist = {} function P(...) io.write(unpack(arg)) @@ -41,6 +43,7 @@ function locheader() local _,line = getsrcline() + if line == nil then line = -1 end if testname == nil then return "\n:" .. line .. ": " else @@ -48,6 +51,11 @@ end end +function err(...) + errfile,errline = getsrcline() + error(unpack(arg)) +end + old_mkdir = mkdir mkdir = function(name) L(locheader(), "mkdir ", name, "\n") @@ -132,9 +140,9 @@ function rename(from, to) L(locheader(), "rename ", from, " ", to, "\n") - local res,err = os.rename(from, to) - if res == nil then - L(err, "\n") + local ok,res = os.rename(from, to) + if ok == nil then + L(res, "\n") return false else return true @@ -143,9 +151,9 @@ function remove(file) L(locheader(), "remove ", file, "\n") - local res,err = os.remove(file) - if res == nil then - L(err, "\n") + local ok,res = os.remove(file) + if ok == nil then + L(res, "\n") return false else return true @@ -178,6 +186,33 @@ return ret end +function background(path, ...) + local ret = {} + local pid = spawn(path, unpack(arg)) + if (pid == -1) then return false end + ret.pid = pid + local mt = {} + mt.__index = mt + mt.finish = function (obj, timeout) + if timeout == nil then timeout = 0 end + local ret, res = timed_wait(obj.pid, timeout) + if (res == -1) then + kill(obj.pid, 15) -- TERM + ret, res = timed_wait(obj.pid, 2) + if (res == -1) then + kill(obj.pid, 9) -- KILL + ret, res = timed_wait(obj.pid, 2) + end + end + return ret + end + mt.wait = function (obj) + local ret,_ = wait(obj.pid) + return ret + end + return setmetatable(ret, mt) +end + function cmd(first, ...) if type(first) == "string" then L(locheader(), first, " ", table.concat(arg, " "), "\n") @@ -244,17 +279,8 @@ L(readfile_q(filename)) end --- std{out,err} can be: --- * false: ignore --- * true: ignore, copy to stdout --- * string: check that it matches the contents --- * nil: must be empty --- stdin can be: --- * true: use existing "stdin" file --- * nil, false: empty input --- * string: contents of string -function check_func(func, ret, stdout, stderr, stdin) - if ret == nil then ret = 0 end +function pre_cmd(stdin, ident) + if ident == nil then ident = "ts-" end if stdin ~= true then local infile = io.open("stdin", "w") if stdin ~= nil and stdin ~= false then @@ -262,94 +288,141 @@ end infile:close() end - os.remove("ts-stdin") - os.rename("stdin", "ts-stdin") + os.remove(ident .. "stdin") + os.rename("stdin", ident .. "stdin") L("stdin:\n") - log_file_contents("ts-stdin") - -- local i, o, e = set_redirect("ts-stdin", "ts-stdout", "ts-stderr") - local redir = set_redirect("ts-stdin", "ts-stdout", "ts-stderr") - local ok, result = pcall(func) - -- redir:restore() - clear_redirect(redir) - -- clear_redirect(i, o, e) + log_file_contents(ident .. "stdin") + return set_redirect(ident .. "stdin", ident .. "stdout", ident .. "stderr") +end + +function post_cmd(result, ret, stdout, stderr, ident) + if ident == nil then ident = "ts-" end L("stdout:\n") - log_file_contents("ts-stdout") + log_file_contents(ident .. "stdout") L("stderr:\n") - log_file_contents("ts-stderr") - if ok == false then - errfile,errline = getsrcline() - error(result, 2) + log_file_contents(ident .. "stderr") + if result ~= ret and ret ~= false then + err("Check failed (return value): wanted " .. ret .. " got " .. result, 3) end - if result ~= ret then - errfile,errline = getsrcline() - error("Check failed (return value): wanted " .. ret .. " got " .. result, 3) - end if stdout == nil then - if fsize("ts-stdout") ~= 0 then - errfile,errline = getsrcline() - error("Check failed (stdout): not empty", 3) + if fsize(ident .. "stdout") ~= 0 then + err("Check failed (stdout): not empty", 3) end elseif type(stdout) == "string" then local realout = io.open("stdout") local contents = realout:read("*a") realout:close() if contents ~= stdout then - errfile,errline = getsrcline() - error("Check failed (stdout): doesn't match", 3) + err("Check failed (stdout): doesn't match", 3) end elseif stdout == true then os.remove("stdout") - os.rename("ts-stdout", "stdout") + os.rename(ident .. "stdout", "stdout") end if stderr == nil then - if fsize("ts-stderr") ~= 0 then - errfile,errline = getsrcline() - error("Check failed (stderr): not empty", 3) + if fsize(ident .. "stderr") ~= 0 then + err("Check failed (stderr): not empty", 3) end elseif type(stderr) == "string" then local realerr = io.open("stderr") local contents = realerr:read("*a") realerr:close() if contents ~= stderr then - errfile,errline = getsrcline() - error("Check failed (stderr): doesn't match", 3) + err("Check failed (stderr): doesn't match", 3) end elseif stderr == true then os.remove("stderr") - os.rename("ts-stderr", "stderr") + os.rename(ident .. "stderr", "stderr") end end +-- std{out,err} can be: +-- * false: ignore +-- * true: ignore, copy to stdout +-- * string: check that it matches the contents +-- * nil: must be empty +-- stdin can be: +-- * true: use existing "stdin" file +-- * nil, false: empty input +-- * string: contents of string + +function bg(torun, ret, stdout, stderr, stdin) + bgid = bgid + 1 + local out = {} + out.prefix = "ts-" .. bgid .. "-" + local redir = pre_cmd(stdin, out.prefix) + out.process = background(unpack(torun)) + redir:restore() + if out.process == false then + err("Failed to start background process\n", 2) + end + bglist[bgid] = out + out.id = bgid + out.retval = nil + out.locstr = locheader() + out.cmd = torun + out.expret = ret + out.expout = stdout + out.experr = stderr + L(out.locstr, "starting background command: ", table.concat(out.cmd, " ")) + local mt = {} + mt.__index = mt + mt.finish = function(obj, timeout) + if obj.retval ~= nil then return end + obj.retval = obj.process:finish(timeout) + table.remove(bglist, obj.id) + L(locheader(), "checking background command from ", out.locstr, + table.concat(out.cmd, " ")) + post_cmd(obj.retval, out.expret, out.expout, out.experr, obj.prefix) + end + mt.wait = function(obj) + if obj.retval ~= nil then return end + obj.retval = obj.process:wait() + table.remove(bglist, obj.id) + L(locheader(), "checking background command from ", out.locstr, + table.concat(out.cmd, " ")) + post_cmd(obj.retval, out.expret, out.expout, out.experr, obj.prefix) + end + return setmetatable(out, mt) +end + +function check_func(func, ret, stdout, stderr, stdin) + if ret == nil then ret = 0 end + local redir = pre_cmd(stdin) + local ok, result = pcall(func) + redir:restore() + if ok == false then + err(result, 2) + end + post_cmd(result, ret, stdout, stderr) +end + function check(first, ...) if type(first) == "function" then check_func(first, unpack(arg)) elseif type(first) == "boolean" then - errfile,errline = getsrcline() - if not first then error("Check failed: false", 2) end + if not first then err("Check failed: false", 2) end elseif type(first) == "number" then if first ~= 0 then - errfile,errline = getsrcline() - error("Check failed: " .. first .. " ~= 0", 2) + err("Check failed: " .. first .. " ~= 0", 2) end else - errfile,errline = getsrcline() - error("Bad argument to check() (" .. type(first) .. ")", 2) + err("Bad argument to check() (" .. type(first) .. ")", 2) end end function skip_if(chk) if chk then - errfile,errline = getsrcline() - error(true, 2) + err(true, 2) end end function xfail_if(chk, ...) - local res,err = pcall(check, unpack(arg)) - if res == false then - if chk then error(false, 2) else error(err, 2) end + local ok,res = pcall(check, unpack(arg)) + if ok == false then + if chk then err(false, 2) else err(err, 2) end else if chk then wanted_fail = true @@ -410,10 +483,13 @@ counts.total = 0 local function runtest(i, tname) + bgid = 0 testname = tname wanted_fail = false local shortname = nil test_root, shortname = go_to_test_dir(testname) + errfile = "" + errline = -1 if i < 100 then P(" ") end if i < 10 then P(" ") end @@ -433,7 +509,11 @@ r = false e = "Could not load driver file " .. driverfile .. " .\n" .. e else + bglist = {} r,e = xpcall(driver, debug.traceback) + for i,b in pairs(bglist) do + b:finish(0) + end restore_env() end if r then ============================================================ --- testsuite.at 33beef0685a0c8139f659e4fc69d5b46b0e77a0c +++ testsuite.at 0061fcad7d9c8da8ed4519e26dd2d1935ab0eccc @@ -635,12 +635,12 @@ m4_include(tests/t_cvsimport.at)# m4_include(tests/t_i18n_file.at)# m4_include(tests/t_fmerge.at)# -m4_include(tests/t_netsync.at) -m4_include(tests/t_netsync_single.at) -m4_include(tests/t_netsync_pubkey.at) -m4_include(tests/t_netsync_repeated.at) -m4_include(tests/t_netsync_unrelated.at) -m4_include(tests/t_disapprove.at) +m4_include(tests/t_netsync.at)# +m4_include(tests/t_netsync_single.at)# +m4_include(tests/t_netsync_pubkey.at)# +m4_include(tests/t_netsync_repeated.at)# +m4_include(tests/t_netsync_unrelated.at)# +m4_include(tests/t_disapprove.at)# m4_include(tests/t_testresult.at) m4_include(tests/t_singlecvs.at) m4_include(tests/t_ls_missing.at) ============================================================ --- testsuite.lua 354a2946c7548b447bda504e476be5666567d54e +++ testsuite.lua 8a7a8643419cbeb1bffacb3c2b00bd28f5e4febf @@ -23,6 +23,13 @@ "address@hidden", unpack(arg)) end +function minhooks_mtn(...) + return raw_mtn("--db=" .. test_root .. "/test.db", + "--keydir", test_root .. "/keys", + "--rcfile", test_root .. "/min_hooks.lua", + "address@hidden", unpack(arg)) +end + function commit(branch) if branch == nil then branch = "testbranch" end check(cmd(mtn("commit", "--message=blah-blah", "--branch", branch)), 0, false, false) @@ -47,7 +54,6 @@ 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(cmd(mtn("db", "init")), 0, false, false) check(cmd(mtn("read", "test_keys")), 0, false, false) @@ -55,6 +61,75 @@ os.remove("test_keys") end + +-- netsync + +netsync_address = nil + +function netsync_setup() + copyfile("test.db", "test2.db") + copy_recursive("keys", "keys2") + copyfile("test.db", "test3.db") + copy_recursive("keys", "keys3") + getstdfile("tests/netsync.lua", "netsync.lua") + netsync_address = "localhost:" .. math.random(20000, 50000) +end + +function netsync_setup_with_notes() + netsync_setup() + getstdfile("tests/netsync_with_notes.lua", "netsync.lua") +end + +function mtn2(...) + return mtn("--db=test2.db", "--keydir=keys2", unpack(arg)) +end + +function mtn3(...) + return mtn("--db=test3.db", "--keydir=keys3", unpack(arg)) +end + +function netsync_serve_start(pat, n, min) + if pat == "" or pat == nil then pat = "*" end + local args = {} + local fn = mtn + table.insert(args, "--dump=_MTN/server_dump") + table.insert(args, "--bind="..netsync_address) + if min then + fn = minhooks_mtn + else + table.insert(args, "--rcfile=netsync.lua") + end + if n ~= nil then + table.insert(args, "--keydir=keys"..n) + table.insert(args, "--db=test"..n..".db") + end + table.insert(args, "serve") + table.insert(args, pat) + local out = bg({fn(unpack(args))}, false, false, false) + -- wait for "beginning service..." + while fsize(out.prefix .. "stderr") == 0 do + sleep(1) + end + return out +end + +function netsync_client_run(oper, pat, res, n) + if pat == "" or pat == nil then pat = "*" end + if n == nil then n = 2 end + check(cmd(mtn("--rcfile=netsync.lua", "--keydir=keys"..n, + "--db=test"..n..".db", oper, netsync_address, pat)), + res, false, false) +end + +function run_netsync(oper, pat) + local srv = netsync_serve_start(pat) + netsync_client_run(oper, pat, 0) + srv:finish() +end + + + + function base_revision() return string.gsub(readfile("_MTN/revision"), "%s*$", "") end @@ -97,6 +172,14 @@ end end +-- maybe this one should go in tester.lua? +function check_same_stdout(cmd1, cmd2) + check(cmd1, 0, true, false) + rename("stdout", "stdout-first") + check(cmd2, 0, true, false) + check(samefile("stdout", "stdout-first")) +end + ------------------------------------------------------------------------ --====================================================================-- ------------------------------------------------------------------------ @@ -128,3 +211,9 @@ table.insert(tests, "tests/importing_CVS_files") table.insert(tests, "tests/importing_files_with_non-english_names") table.insert(tests, "tests/external_unit_test_of_the_line_merger") +table.insert(tests, "tests/exchanging_work_via_netsync") +table.insert(tests, "tests/single_manifest_netsync") +table.insert(tests, "tests/netsync_transfers_public_keys") +table.insert(tests, "tests/repeatedly_exchanging_work_via_netsync") +table.insert(tests, "tests/(normal)_netsync_on_partially_unrelated_revisions") +table.insert(tests, "tests/disapproving_of_a_revision") ============================================================ --- unix/process.cc 93c62c374ed212a5612d02dfe5d22eeecdd6456c +++ unix/process.cc 04fb1d79c00ec3dddb30fab643b71bef0006cb13 @@ -105,10 +105,23 @@ } } -int process_wait(pid_t pid, int *res) +int process_wait(pid_t pid, int *res, int timeout) { int status; - pid = waitpid(pid, &status, 0); + int flags = 0; + if (timeout == -1) + timeout = 0; + else + flags |= WNOHANG; + int r; + for (r = 0; r == 0 && timeout >= 0; --timeout) + { + r = waitpid(pid, &status, flags); + if (r == 0 && timeout > 0) + process_sleep(1); + } + if (r == 0) + return -1; if (WIFEXITED(status)) *res = WEXITSTATUS(status); else ============================================================ --- win32/process.cc 615b38daf893dd7dd4fc7856ba36684795462efc +++ win32/process.cc cd470989510d05f0a9e619b880183df66b5df6f3 @@ -144,10 +144,16 @@ return (pid_t)pi.hProcess; } -int process_wait(pid_t pid, int *res) +int process_wait(pid_t pid, int *res, int timeout) { HANDLE hProcess = (HANDLE)pid; - if (WaitForSingleObject(hProcess, INFINITE)==WAIT_FAILED) + DWORD time = INFINITE + if (timeout != -1) + time = timeout * 1000; + DWORD r = WaitForSingleObject(hProcess, time); + if (r == WAIT_TIMEOUT) + return -1; + if (r == WAIT_FAILED) { CloseHandle(hProcess); /* May well not work, but won't harm */ return -1;