# # # delete "tests/t_add_owndb.at" # # delete "tests/t_automate_ancestors.at" # # delete "tests/t_can_execute.at" # # delete "tests/t_cat_file_by_name.at" # # delete "tests/t_checkout_creates_log.at" # # delete "tests/t_command_completion.at" # # delete "tests/t_commit_log_1.at" # # delete "tests/t_commit_log_2.at" # # delete "tests/t_commit_validate.at" # # delete "tests/t_database_check.at" # # delete "tests/t_diff_binary.at" # # delete "tests/t_diff_restrict.at" # # delete "tests/t_dropkey_1.at" # # delete "tests/t_dropkey_2.at" # # delete "tests/t_empty_env.at" # # delete "tests/t_empty_id_completion.at" # # delete "tests/t_empty_path.at" # # delete "tests/t_epoch.at" # # delete "tests/t_epoch_server.at" # # delete "tests/t_epoch_unidirectional.at" # # delete "tests/t_merge_5.at" # # delete "tests/t_merge_rename_file_and_rename_dir.at" # # delete "tests/t_netsync_absorbs.at" # # delete "tests/t_netsync_checks_server_key.at" # # delete "tests/t_netsync_defaults.at" # # delete "tests/t_netsync_set_defaults.at" # # delete "tests/t_netsync_sigpipe.at" # # delete "tests/t_rename_attr.at" # # delete "tests/t_setup_creates_log.at" # # delete "tests/t_short_opts.at" # # delete "tests/t_vars.at" # # add_dir "tests/(minor)_add_own_db" # # add_dir "tests/automate_ancestors" # # add_dir "tests/can_execute_things" # # add_dir "tests/cat_-r_REV_PATH" # # add_dir "tests/checkout_creates__MTN_log" # # add_dir "tests/command_completion" # # add_dir "tests/commit_using__MTN_log" # # add_dir "tests/commit_validation_lua_hook" # # add_dir "tests/commit_w_o__MTN_log_being_present" # # add_dir "tests/database_check" # # add_dir "tests/diff_a_binary_file" # # add_dir "tests/diff_respects_restrictions" # # add_dir "tests/drop_a_public_and_private_key" # # add_dir "tests/drop_a_public_key" # # add_dir "tests/empty_environment" # # add_dir "tests/empty_id_completion" # # add_dir "tests/empty_string_as_a_path_name" # # add_dir "tests/merge_rename_file_and_rename_dir" # # add_dir "tests/netsync_client_absorbs_and_checks_epochs" # # add_dir "tests/netsync_client_absorbs_server_key" # # add_dir "tests/netsync_default_server_pattern" # # add_dir "tests/netsync_default_server_pattern_setting" # # add_dir "tests/netsync_epochs_are_not_sent_upstream_by_pull" # # add_dir "tests/netsync_is_not_interrupted_by_SIGPIPE" # # add_dir "tests/netsync_server_absorbs_and_checks_epochs" # # add_dir "tests/netsync_verifies_server_keys" # # add_dir "tests/rename_moves_attributes" # # add_dir "tests/setup_creates__MTN_log" # # add_dir "tests/short_options_work_correctly" # # add_dir "tests/test_a_merge_5" # # add_dir "tests/vars" # # add_file "tests/(minor)_add_own_db/__driver__.lua" # content [1fb176fe6f10cb4b9976a595536c715d2b904323] # # add_file "tests/automate_ancestors/__driver__.lua" # content [a37170def6261cd8ae768f8d8cf336f2f416a370] # # add_file "tests/can_execute_things/__driver__.lua" # content [d011bd5b0f3f446bd537e8a096ba9939014bc49b] # # add_file "tests/can_execute_things/nix-cphook.lua" # content [e6b4670d1e018cdd60f60df42db92e8123260ca7] # # add_file "tests/can_execute_things/win-cphook.lua" # content [1bb87b17c4d7d4d168642e31f3a7999a8806bae8] # # add_file "tests/cat_-r_REV_PATH/__driver__.lua" # content [ff8cbb19e14aab453d2e9209ef30837b48d76b13] # # add_file "tests/checkout_creates__MTN_log/__driver__.lua" # content [fa6cdde15c67e65653df35d3ae90e68da70ff8ac] # # add_file "tests/checkout_creates__MTN_log/commit_log.lua" # content [09c926209c317efc447dbe6448fe891c2d86e958] # # add_file "tests/command_completion/__driver__.lua" # content [ee0178f91217398eb542779dc337333fbab2e86d] # # add_file "tests/commit_using__MTN_log/__driver__.lua" # content [c85f9af921ff17ea15565e628dc199fbd892700c] # # add_file "tests/commit_using__MTN_log/commit_log.lua" # content [09c926209c317efc447dbe6448fe891c2d86e958] # # add_file "tests/commit_validation_lua_hook/__driver__.lua" # content [66264652b87eb7429c905ba75b193ac3ef0d69e8] # # add_file "tests/commit_validation_lua_hook/commit_validate.lua" # content [37908f383b360ab75b2086f801521d9b53318394] # # add_file "tests/commit_validation_lua_hook/errmsg" # content [d461be0f9de73556ab41089ae260d9a655dcc3f9] # # add_file "tests/commit_w_o__MTN_log_being_present/__driver__.lua" # content [c8c4d144c85803c4b9bcb986bc71543c4d4ef44d] # # add_file "tests/database_check/__driver__.lua" # content [4d73c49472d143e5e414f793e50a336b5d1d3d24] # # add_file "tests/diff_a_binary_file/__driver__.lua" # content [503002e82542225d30db3f1d366dd02bfb84ea9d] # # add_file "tests/diff_a_binary_file/binary" # content [08162783141d2b83def323d3039e0fc5902c7c1d] # # add_file "tests/diff_respects_restrictions/__driver__.lua" # content [36d9cda043eac34e2b7bb4cfe3395bf4ef971ff6] # # add_file "tests/drop_a_public_and_private_key/__driver__.lua" # content [2157acce39fb10e5d2144ef8bfd419e3c83ffb89] # # add_file "tests/drop_a_public_key/__driver__.lua" # content [64c38cebf336034965302baefa2efbb5ee3867f3] # # add_file "tests/drop_a_public_key/pubkey.txt" # content [e72d856eb005368ca08cbf73479f3821329cb586] # # add_file "tests/empty_environment/__driver__.lua" # content [db8cb7bde7a670621710d0149a6167d84e7a12d0] # # add_file "tests/empty_id_completion/__driver__.lua" # content [ae08194e312afcf366e6878679f030d0932e1f63] # # add_file "tests/empty_string_as_a_path_name/__driver__.lua" # content [d9a7dcd36790a95523614f361b470ebe0a807515] # # add_file "tests/merge_rename_file_and_rename_dir/__driver__.lua" # content [0fd8b1102d55c8b335f0a20eac5abd485a35fa0b] # # add_file "tests/netsync_client_absorbs_and_checks_epochs/__driver__.lua" # content [0f422f4face2e53b5371d7f4b3a9ef17259b7503] # # add_file "tests/netsync_client_absorbs_server_key/__driver__.lua" # content [0cbcb51504ad96f5bc0bc319afd59324c7864aa7] # # add_file "tests/netsync_default_server_pattern/__driver__.lua" # content [9d6bfba198be151bc2dea9365694d0c8af9481eb] # # add_file "tests/netsync_default_server_pattern_setting/__driver__.lua" # content [5e7636e39a861076f1e2ef44ab71b31bf09d3320] # # add_file "tests/netsync_epochs_are_not_sent_upstream_by_pull/__driver__.lua" # content [132cf3ec3c4a54225a1da51ec500c262bedf4dd4] # # add_file "tests/netsync_is_not_interrupted_by_SIGPIPE/__driver__.lua" # content [39bccb461318f1b4c5a989cc8216416dcffe4d85] # # add_file "tests/netsync_server_absorbs_and_checks_epochs/__driver__.lua" # content [cd53ea129784c1c830ac8e46e8118f6432ce713a] # # add_file "tests/netsync_verifies_server_keys/__driver__.lua" # content [3784142a3b85cfc0a791a2ea42045b4e35c40024] # # add_file "tests/rename_moves_attributes/__driver__.lua" # content [1c100548abe65110e89fa57d7a271abd1a65f904] # # add_file "tests/setup_creates__MTN_log/__driver__.lua" # content [315fa7b0899ae36ead61b25da7a98ee8c543c87e] # # add_file "tests/short_options_work_correctly/__driver__.lua" # content [42d40c67ca2f855414d90caf721881601cbc01f6] # # add_file "tests/test_a_merge_5/__driver__.lua" # content [0f0e4d7042ceb2fe560c0e8b082bbaabc265e61c] # # add_file "tests/test_a_merge_5/correct" # content [5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b] # # add_file "tests/test_a_merge_5/left" # content [5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b] # # add_file "tests/test_a_merge_5/parent" # content [abd633b6089b43c3097b08ab5c44a9b1d40472eb] # # add_file "tests/test_a_merge_5/right" # content [8bc1e710ca85316767395910c1e6afd03fdd9c6c] # # add_file "tests/vars/__driver__.lua" # content [17630a0ac1fac4a75582a73063d987c6b4442502] # # patch "tester.cc" # from [fe9ae11945602183ddc91bb850dd5a1de4ea4525] # to [15f9df6af209097db87c510ca37c8c93f4a4e6e9] # # patch "tester.lua" # from [d71188603ab47fded0896bad4d89444fe49205f0] # to [2d9160c79827476de8af60abde5c6f7ea0a6f822] # # patch "testsuite.at" # from [7ac716d85aeee1483af8a1891243a9daa3fa7a53] # to [657b10b3bf7ccaa263cff9617210401fc6a5c4cd] # # patch "testsuite.lua" # from [f61bf454ad6bfaa304208da8de782c89e9715909] # to [3e5cb0ddb4c7e5b49f076e9fbf1d5d3c2a6cb5e9] # ============================================================ --- tests/(minor)_add_own_db/__driver__.lua 1fb176fe6f10cb4b9976a595536c715d2b904323 +++ tests/(minor)_add_own_db/__driver__.lua 1fb176fe6f10cb4b9976a595536c715d2b904323 @@ -0,0 +1,28 @@ + +mtn_setup() + +--Adding the current in-use DB should fail +-- ...It *really* seems like adding the db to the db is something that should be caught and an error message thrown... +-- (What's revert supposed to do when you revert the db? :-) +-- ... +-- and add a note in a comment that "revert" is the case that really moves this +-- from being "stupid user tricks" to "something we should protect users from" :-) +check(mtn("add", "test.db"), 0, false, false) +check(mtn("ls", "known"), 0, true, false) +check(not qgrep("'test.db'", "stdout")) + +check(mtn("add", "."), 0, false, false) +check(mtn("ls", "known"), 0, true, false) +check(not qgrep("'test.db'", "stdout")) + +mkdir("subdir") +copyfile("test.db", "subdir/test.db") + +check(mtn("--db=subdir/test.db", "add", "subdir/test.db"), 0, false, false) +check(mtn("--db=subdir/test.db", "ls", "known"), 0, true, false) +check(not qgrep("'subdir/test.db'", "stdout")) + +-- If it's not an in-use DB, it should work, though +check(mtn("add", "subdir/test.db"), 0, false, false) +check(mtn("ls", "known"), 0, true, false) +check(qgrep("subdir/test.db", "stdout")) ============================================================ --- tests/automate_ancestors/__driver__.lua a37170def6261cd8ae768f8d8cf336f2f416a370 +++ tests/automate_ancestors/__driver__.lua a37170def6261cd8ae768f8d8cf336f2f416a370 @@ -0,0 +1,79 @@ + +mtn_setup() + +check(mtn("automate", "ancestors", "c7539264e83c5d6af4c792f079b5d46e9c128665"), 1, false, false) + +-- A +-- / \ +-- B C +-- |\ +-- D E +-- \/ +-- F +revs = {} + +addfile("testfile", "A") +commit() +revs.a = base_revision() + +writefile("testfile", "B") +commit() +revs.b = base_revision() + +revert_to(revs.a) + +writefile("testfile", "C") +commit() +revs.c = base_revision() + +writefile("testfile", "D") +commit() +revs.d = base_revision() + +revert_to(revs.c) + +addfile("otherfile", "E") +commit() +revs.e = base_revision() + +check(mtn("explicit_merge", revs.d, revs.e, "testbranch"), 0, false, false) +check(mtn("update"), 0, false, false) +revs.f = base_revision() + +check(revs.f ~= revs.d) +check(revs.f ~= revs.e) + +-- Now do some checks + +check(mtn("automate", "ancestors", revs.a), 0, 0, false) + +check(mtn("automate", "ancestors", revs.b), 0, true, false) +canonicalize("stdout") +writefile("tmp", revs.a.."\n") +check(samefile("tmp", "stdout")) + +check(mtn("automate", "ancestors", revs.e), 0, true, false) +canonicalize("stdout") +tmp = {revs.a, revs.c} +table.sort(tmp) +writefile("tmp", table.concat(tmp, "\n").."\n") +check(samefile("tmp", "stdout")) + +check(mtn("automate", "ancestors", revs.f), 0, true, false) +canonicalize("stdout") +tmp = {revs.d, revs.a, revs.c, revs.e} +table.sort(tmp) +writefile("tmp", table.concat(tmp, "\n").."\n") +check(samefile("tmp", "stdout")) + +check(mtn("automate", "ancestors", revs.d, revs.f), 0, true, false) +canonicalize("stdout") +tmp = {revs.d, revs.a, revs.c, revs.e} +table.sort(tmp) +writefile("tmp", table.concat(tmp, "\n").."\n") +check(samefile("tmp", "stdout")) + +check(mtn("automate", "ancestors", revs.a, revs.b, revs.c), 0, true, false) +canonicalize("stdout") +writefile("tmp", revs.a.."\n") +check(samefile("tmp", "stdout")) ============================================================ --- tests/can_execute_things/__driver__.lua d011bd5b0f3f446bd537e8a096ba9939014bc49b +++ tests/can_execute_things/__driver__.lua d011bd5b0f3f446bd537e8a096ba9939014bc49b @@ -0,0 +1,16 @@ + +if existsonpath("cp") then + getfile("nix-cphook.lua", "cphook.lua") +elseif existsonpath("xcopy") then + getfile("win-cphook.lua", "cphook.lua") +else + skip_if(true) +end + +mtn_setup() + +writefile("testfile", "blah blah") + +check(mtn("add", "cphook.lua"), 0, false, false) +check(mtn("--branch=testbranch", "--rcfile=cphook.lua", "commit", "--message=test"), 0, false, false) +check(exists("testfile.copied")) ============================================================ --- tests/can_execute_things/nix-cphook.lua e6b4670d1e018cdd60f60df42db92e8123260ca7 +++ tests/can_execute_things/nix-cphook.lua e6b4670d1e018cdd60f60df42db92e8123260ca7 @@ -0,0 +1,9 @@ +function note_commit(new_id, certs) + local pid + local ret = -1 + pid = spawn("cp", "testfile", "testfile.copied") + if (pid == -1) then + return nil + end + ret, pid = wait(pid) +end ============================================================ --- tests/can_execute_things/win-cphook.lua 1bb87b17c4d7d4d168642e31f3a7999a8806bae8 +++ tests/can_execute_things/win-cphook.lua 1bb87b17c4d7d4d168642e31f3a7999a8806bae8 @@ -0,0 +1,9 @@ +function note_commit(new_id, certs) + local pid + local ret = -1 + pid = spawn("xcopy", "testfile", "testfile.copied") + if (pid == -1) then + return nil + end + ret, pid = wait(pid) +end ============================================================ --- tests/cat_-r_REV_PATH/__driver__.lua ff8cbb19e14aab453d2e9209ef30837b48d76b13 +++ tests/cat_-r_REV_PATH/__driver__.lua ff8cbb19e14aab453d2e9209ef30837b48d76b13 @@ -0,0 +1,43 @@ + +mtn_setup() +revs = {} + +writefile("r0testfile", "r0 test file") +writefile("r0otherfile", "r0 other file") +writefile("r1testfile", "r1 test file") +writefile("subfile", "data in subfile") + +copyfile("r0testfile", "testfile") +copyfile("r0otherfile", "otherfile") +mkdir("subdir") +copyfile("subfile", "subdir/testfile") +check(mtn("add", "testfile", "otherfile", "subdir/testfile"), 0, false, false) +commit() +revs[0] = base_revision() + +copyfile("r1testfile", "testfile") +commit() +revs[1] = base_revision() + +check(mtn("cat", "-r", revs[0], "testfile"), 0, true, false) +canonicalize("stdout") +check(samefile("stdout", "r0testfile")) + +check(mtn("cat", "-r", revs[0], "otherfile"), 0, true, false) +canonicalize("stdout") +check(samefile("stdout", "r0otherfile")) + +check(mtn("cat", "-r", revs[1], "testfile"), 0, true, false) +canonicalize("stdout") +check(samefile("stdout", "r1testfile")) + +check(indir("subdir", mtn("cat", "-r", revs[0], "testfile")), 0, true, false) +check(samefile("stdout", "subfile")) + +remove_recursive("_MTN") + +check(mtn("cat", "-r", revs[0], "testfile"), 0, true, false) +check(samefile("stdout", "r0testfile")) + +check(mtn("cat", "-r", revs[0], "no_such_file"), 1, false, false) +check(mtn("cat", "-r", revs[0], ""), 1, false, false) ============================================================ --- tests/checkout_creates__MTN_log/__driver__.lua fa6cdde15c67e65653df35d3ae90e68da70ff8ac +++ tests/checkout_creates__MTN_log/__driver__.lua fa6cdde15c67e65653df35d3ae90e68da70ff8ac @@ -0,0 +1,18 @@ + +mtn_setup() + +getfile("commit_log.lua") + +writefile("_MTN/log", "Log entry") + +writefile("input.txt", "version 0 of the file") + +check(mtn("add", "input.txt"), 0, false, false) + +check(mtn("--branch=testbranch", "--rcfile=commit_log.lua", "commit"), 0, false, false) + +check(mtn("--branch=testbranch", "co", "testbranch")) + +check(exists("testbranch/_MTN/log")) +check(fsize("_MTN/log") == 0) +check(fsize("testbranch/_MTN/log") == 0) ============================================================ --- tests/checkout_creates__MTN_log/commit_log.lua 09c926209c317efc447dbe6448fe891c2d86e958 +++ tests/checkout_creates__MTN_log/commit_log.lua 09c926209c317efc447dbe6448fe891c2d86e958 @@ -0,0 +1,3 @@ +function edit_comment(summary, user_log_file) + return user_log_file +end ============================================================ --- tests/command_completion/__driver__.lua ee0178f91217398eb542779dc337333fbab2e86d +++ tests/command_completion/__driver__.lua ee0178f91217398eb542779dc337333fbab2e86d @@ -0,0 +1,10 @@ + +mtn_setup() + +check(mtn("status"), 0, false, false) +check(mtn("st"), 0, false, false) +check(mtn("s"), 1, false, false) + +check(mtn("diff"), 0, false, false) +check(mtn("dif"), 0, false, false) +check(mtn("di"), 1, false, false) ============================================================ --- tests/commit_using__MTN_log/__driver__.lua c85f9af921ff17ea15565e628dc199fbd892700c +++ tests/commit_using__MTN_log/__driver__.lua c85f9af921ff17ea15565e628dc199fbd892700c @@ -0,0 +1,18 @@ + +mtn_setup() + +getfile("commit_log.lua") + +writefile("_MTN/log", "Log entry") + +writefile("input.txt", "version 0 of the file") + +check(mtn("add", "input.txt"), 0, false, false) + +check(mtn("--branch=testbranch", "--rcfile=commit_log.lua", "commit"), 0, false, false) + +tsha = base_revision() +check(exists("_MTN/log")) +check(fsize("_MTN/log") == 0) +check(mtn("ls", "certs", tsha), 0, true, false) +check(qgrep('Log entry', "stdout")) ============================================================ --- tests/commit_using__MTN_log/commit_log.lua 09c926209c317efc447dbe6448fe891c2d86e958 +++ tests/commit_using__MTN_log/commit_log.lua 09c926209c317efc447dbe6448fe891c2d86e958 @@ -0,0 +1,3 @@ +function edit_comment(summary, user_log_file) + return user_log_file +end ============================================================ --- tests/commit_validation_lua_hook/__driver__.lua 66264652b87eb7429c905ba75b193ac3ef0d69e8 +++ tests/commit_validation_lua_hook/__driver__.lua 66264652b87eb7429c905ba75b193ac3ef0d69e8 @@ -0,0 +1,12 @@ + +mtn_setup() + +getfile("commit_validate.lua") + +writefile("input.txt", "version 0 of the file") + +check(mtn("add", "input.txt"), 0, false, false) +getfile("errmsg") +check(mtn("--branch=testbranch", "--rcfile=commit_validate.lua", "commit", "-m", "denyme"), 1, false, true) +check(samefile("errmsg", "stderr")) +check(mtn("--branch=testbranch", "--rcfile=commit_validate.lua", "commit", "-m", "allowme"), 0, false, false) ============================================================ --- tests/commit_validation_lua_hook/commit_validate.lua 37908f383b360ab75b2086f801521d9b53318394 +++ tests/commit_validation_lua_hook/commit_validate.lua 37908f383b360ab75b2086f801521d9b53318394 @@ -0,0 +1,10 @@ +function validate_commit_message(message, info) + if (not string.find(info, "input.txt")) then + return false, "Wrong info message" + end + if (message == "denyme") then + return false, "input.txt" + end + + return true, "" +end ============================================================ --- tests/commit_validation_lua_hook/errmsg d461be0f9de73556ab41089ae260d9a655dcc3f9 +++ tests/commit_validation_lua_hook/errmsg d461be0f9de73556ab41089ae260d9a655dcc3f9 @@ -0,0 +1,2 @@ +mtn: beginning commit on branch 'testbranch' +mtn: misuse: log message rejected: input.txt ============================================================ --- tests/commit_w_o__MTN_log_being_present/__driver__.lua c8c4d144c85803c4b9bcb986bc71543c4d4ef44d +++ tests/commit_w_o__MTN_log_being_present/__driver__.lua c8c4d144c85803c4b9bcb986bc71543c4d4ef44d @@ -0,0 +1,14 @@ + +mtn_setup() + +remove("_MTN/log") + +writefile("input.txt", "version 0 of the file") + +check(mtn("add", "input.txt"), 0, false, false) + +commit("testbranch", "Log entry") + +tsha = base_revision() +check(mtn("ls", "certs", tsha), 0, true, false) +check(qgrep('Log entry', "stdout")) ============================================================ --- tests/database_check/__driver__.lua 4d73c49472d143e5e414f793e50a336b5d1d3d24 +++ tests/database_check/__driver__.lua 4d73c49472d143e5e414f793e50a336b5d1d3d24 @@ -0,0 +1,116 @@ + +mtn_setup() + +writefile("file1", "file 1") +writefile("file2", "file 2") +writefile("file3", "file 3") + +writefile("fileX", "coopers") + +writefile("fileY", "vitamin") + +revs = {} +files = {} +rosters = {} + +function dbex(...) + check(mtn("db", "execute", string.format(unpack(arg))), 0, false, false) +end + +check(mtn("add", "file1"), 0, false, false) +commit("test", "add file1") +revs[1] = base_revision() +check(raw_mtn("db", "execute", "select id from rosters"), 0, true, false) +check(tail("stdout", 1), 0, true) +rosters[1] = trim(readfile("stdout")) + +check(mtn("add", "file2"), 0, false, false) +commit("test", "add file2") +revs[2] = base_revision() +files[2] = sha1("file2") + +check(mtn("add", "file3"), 0, false, false) +commit("test", "add file3") +files[3] = sha1("file3") +revs[3] = base_revision() + +check(mtn("db", "check", "--ticker=dot"), 0, false, true) +check(qgrep('database is good', "stderr")) + +-- remove file2 from the database invalidating roster2 and roster3 +-- both of which include this file + +dbex("delete from files where id='%s'", files[2]) + +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(not qgrep('database is good', "stderr")) +check(qgrep('problems detected', "stderr")) +check(qgrep('1 missing file', "stderr")) +check(qgrep('2 incomplete roster', "stderr")) +check(qgrep('2 incomplete revision', "stderr")) +check(qgrep('total problems detected: 5', "stderr")) +check(qgrep('5 serious', "stderr")) + + +-- add an unreferenced file +copyfile("fileX", "stdin") +check(mtn("fload"), 0, false, false, true) +-- create an unreferenced roster by deleting the revision. Note that this will increment +-- the "missing revision" count by one for further checks +check(mtn("add", "fileY"), 0, false, false) +commit("test", "to be removed") +revs[4] = base_revision() +dbex("delete from revisions where id='%s'", revs[4]) +-- revert to the old workspace state +writefile("_MTN/revision", revs[3]) +-- remove another file too +dbex("delete from files where id='%s'", files[3]) + +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('1 unreferenced file', "stderr")) +check(qgrep('1 unreferenced roster', "stderr")) +check(qgrep('2 missing files', "stderr")) + +dbex("delete from revision_ancestry") +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('2 mismatched parent', "stderr")) +check(qgrep('2 mismatched child', "stderr")) + +-- bogus revision ancestry entries + +xdelta_cc = "877cfe29db0f60dec63439857fe78673b9d55346" +xdelta_hh = "68d15dc01398c7bb375b1a90fbb420bebef1bac7" + +dbex("insert into revision_ancestry values('%s', '%s')", xdelta_cc, xdelta_hh) +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('3 mismatched parent', "stderr")) +check(qgrep('3 mismatched child', "stderr")) +check(qgrep('3 missing revision', "stderr")) + +dbex("delete from roster_deltas where id='%s'", rosters[1]) +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +-- ROSTER TODO: need check_sane_history equivalent in db check +--check(grep '3 revisions with bad history' stderr, 0, false, false) + +dbex("delete from revisions where id='%s'", revs[1]) +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('4 missing revision', "stderr")) +-- ROSTER TODO +--check(grep '2 revisions with bad history' stderr, 0, false, false) + +writefile("tosum", revs[2]..":comment:this is a test:address@hidden:bogus sig") +hash = sha1("tosum") + +dbex("insert into revision_certs values ('%s', '%s', 'comment', 'this is a test', 'address@hidden', 'bogus sig')", hash, revs[2]) +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('1 bad sig', "stderr")) + +dbex("delete from revision_certs where name = 'date'") +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('2 missing certs', "stderr")) +check(qgrep('4 mismatched certs', "stderr")) + +dbex("delete from public_keys") +check(mtn("db", "check", "--ticker=dot"), 1, false, true) +check(qgrep('1 missing key', "stderr")) +check(qgrep('13 unchecked signatures', "stderr")) ============================================================ --- tests/diff_a_binary_file/__driver__.lua 503002e82542225d30db3f1d366dd02bfb84ea9d +++ tests/diff_a_binary_file/__driver__.lua 503002e82542225d30db3f1d366dd02bfb84ea9d @@ -0,0 +1,9 @@ + +mtn_setup() + +getfile("binary") + +check(mtn("add", "binary"), 0, false, false) +check(mtn("status"), 0, false, false) +check(mtn("diff"), 0, true, false) +check(not qgrep("[^[:print:]]", "stdout")) ============================================================ # tests/diff_a_binary_file/binary is binary ============================================================ --- tests/diff_respects_restrictions/__driver__.lua 36d9cda043eac34e2b7bb4cfe3395bf4ef971ff6 +++ tests/diff_respects_restrictions/__driver__.lua 36d9cda043eac34e2b7bb4cfe3395bf4ef971ff6 @@ -0,0 +1,32 @@ + +mtn_setup() +revs = {} + +addfile("file1", "1: data 1") +addfile("file2", "2: data 1") +commit() +revs[1] = base_revision() + +writefile("file1", "1: data 2") +writefile("file2", "2: data 2") +commit() +revs[2] = base_revision() + +writefile("file1", "1: data 3") +writefile("file2", "2: data 3") + +check(mtn("diff", "file1"), 0, true, false) +check(qgrep("file1", "stdout")) +check(not qgrep("file2", "stdout")) + +check(mtn("diff", "--revision", revs[1], "file1"), 0, true, false) +check(qgrep("file1", "stdout")) +check(not qgrep("file2", "stdout")) + +check(mtn("diff", "--revision", revs[1], "--revision", revs[2], "file1"), 0, true, false) +check(qgrep("file1", "stdout")) +check(not qgrep("file2", "stdout")) + +check(mtn("diff", "--revision", revs[2], "--revision", revs[1], "file1"), 0, true, false) +check(qgrep("file1", "stdout")) +check(not qgrep("file2", "stdout")) ============================================================ --- tests/drop_a_public_and_private_key/__driver__.lua 2157acce39fb10e5d2144ef8bfd419e3c83ffb89 +++ tests/drop_a_public_and_private_key/__driver__.lua 2157acce39fb10e5d2144ef8bfd419e3c83ffb89 @@ -0,0 +1,18 @@ + +mtn_setup() + +check(mtn("genkey", "address@hidden"), 0, false, false, string.rep("address@hidden", 2)) + +check(mtn("privkey", "address@hidden"), 0, true, false) + +check(qgrep('address@hidden', "stdout")) + +check(mtn("dropkey", "address@hidden"), 0, false, false) + +check(mtn("privkey", "address@hidden"), 1, false, true) + +check(qgrep('do not exist', "stderr")) + +check(mtn("pubkey", "address@hidden"), 1, false, true) + +check(qgrep('does not exist', "stderr")) ============================================================ --- tests/drop_a_public_key/__driver__.lua 64c38cebf336034965302baefa2efbb5ee3867f3 +++ tests/drop_a_public_key/__driver__.lua 64c38cebf336034965302baefa2efbb5ee3867f3 @@ -0,0 +1,16 @@ + +mtn_setup() + +getfile("pubkey.txt", "stdin") + +check(mtn("read"), 0, false, false, true) + +check(mtn("pubkey", "address@hidden"), 0, true, false) + +check(qgrep('address@hidden', "stdout")) + +check(mtn("dropkey", "address@hidden"), 0, false, false) + +check(mtn("pubkey", "address@hidden"), 1, false, true) + +check(qgrep('does not exist', "stderr")) ============================================================ --- tests/drop_a_public_key/pubkey.txt e72d856eb005368ca08cbf73479f3821329cb586 +++ tests/drop_a_public_key/pubkey.txt e72d856eb005368ca08cbf73479f3821329cb586 @@ -0,0 +1,5 @@ +[pubkey address@hidden +MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCPUdR/bM41m2KIpS0eXlTG91PSWvOUdwY4 +6aKd+DXZFma8Hi00Wvwmr+0JJdWqPwyxR/Dr2a2Z7Db76lUiNlhvRw3yoKP2ip9Jjfe0LReG +5aJ5u1l5L5VPiZ5iZq9PjxNDAYASpb89yBT7BJZ6OAXuE9zHFR506Apg7UB4Em184wIBEQ== +[end] ============================================================ --- tests/empty_environment/__driver__.lua db8cb7bde7a670621710d0149a6167d84e7a12d0 +++ tests/empty_environment/__driver__.lua db8cb7bde7a670621710d0149a6167d84e7a12d0 @@ -0,0 +1,19 @@ + +skip_if(not existsonpath("env")) +mtn_setup() + +function noenv_mtn(...) + return {"env", "-i", unpack(mtn(unpack(arg)))} +end + +--check(if test "$OSTYPE" = "msys"; then +-- cp $(which libiconv-2.dll) . +-- cp $(which zlib1.dll) . +--fi) + +check(noenv_mtn("--help"), 2, false, false) +writefile("testfile", "blah blah") +check(noenv_mtn("add", "testfile"), 0, false, false) +check(noenv_mtn("commit", "--branch=testbranch", "--message=foo"), 0, false, false) + +check(false) -- need to fix for windows ============================================================ --- tests/empty_id_completion/__driver__.lua ae08194e312afcf366e6878679f030d0932e1f63 +++ tests/empty_id_completion/__driver__.lua ae08194e312afcf366e6878679f030d0932e1f63 @@ -0,0 +1,5 @@ + +mtn_setup() + +-- regression test: completing the revision "" doesn't crash +check(mtn("cat", "-r", "", "nosuchfile"), 1, false, false) ============================================================ --- tests/empty_string_as_a_path_name/__driver__.lua d9a7dcd36790a95523614f361b470ebe0a807515 +++ tests/empty_string_as_a_path_name/__driver__.lua d9a7dcd36790a95523614f361b470ebe0a807515 @@ -0,0 +1,18 @@ + +mtn_setup() + +addfile("testfile", "blah blah") +commit() +rev = base_revision() + +mkdir("foo") +check(indir("foo", mtn("setup", "--branch=testbranch", "")), 1, false, false) +check(indir("foo", mtn("checkout", "--revision", rev, "")), 1, false, false) +check(indir("foo", mtn("checkout", "--branch=testbranch", "")), 1, false, false) + +check(mtn("add", ""), 1, false, false) +check(mtn("drop", ""), 1, false, false) +check(mtn("rename", "testfile", ""), 1, false, false) +check(mtn("rename", "", "otherfile"), 1, false, false) + +check(mtn("revert", ""), 1, false, false) ============================================================ --- tests/merge_rename_file_and_rename_dir/__driver__.lua 0fd8b1102d55c8b335f0a20eac5abd485a35fa0b +++ tests/merge_rename_file_and_rename_dir/__driver__.lua 0fd8b1102d55c8b335f0a20eac5abd485a35fa0b @@ -0,0 +1,31 @@ + +mtn_setup() + +mkdir("foo") +writefile("foo/bar", "foo bar file") + +-- common ancestor + +check(mtn("add", "foo"), 0, false, false) +commit() +base = base_revision() + +-- rename directory + +rename("foo", "foof") +check(mtn("rename", "foo", "foof"), 0, false, false) +commit() + +-- rename file in directory + +revert_to(base) +rename("foo/bar", "foo/barf") +check(mtn("rename", "foo/bar", "foo/barf"), 0, false, false) +commit() + +-- merge heads to arrive at foof/barf + +check(mtn("merge"), 0, false, false) +check(mtn("co", "dir"), 0, false, false) +check(exists("dir/foof")) +check(exists("dir/foof/barf")) ============================================================ --- tests/netsync_client_absorbs_and_checks_epochs/__driver__.lua 0f422f4face2e53b5371d7f4b3a9ef17259b7503 +++ tests/netsync_client_absorbs_and_checks_epochs/__driver__.lua 0f422f4face2e53b5371d7f4b3a9ef17259b7503 @@ -0,0 +1,55 @@ + +mtn_setup() +netsync.setup() +revs = {} + +addfile("testfile", "version 0 data") +commit() +revs[0] = base_revision() + +netsync.pull("testbranch") + +-- check that the second db got our epoch +check_same_stdout(mtn("list", "epochs"), mtn2("list", "epochs")) + +-- check that epochs are only sent for netsync'ed branches +check(mtn2("list", "epochs"), 0, true, false) +rename("stdout", "orig-epochs") +addfile("testfile2", "other data") +commit("otherbranch") +-- Run an irrelevant netsync, just to force epochs to be regenerated +srv = netsync.start("otherbranch") +srv:sync("otherbranch", 3) +srv:finish() +-- Run the real netsync +netsync.pull("testbranch") +check(mtn2("list", "epochs"), 0, true, false) +rename("stdout", "new-epochs") +check(samefile("orig-epochs", "new-epochs")) +check_different_stdout(mtn("list", "epochs"), mtn2("list", "epochs")) + +addfile("testfile3", "some data") +commit() +revs[1] = base_revision() + +-- change the epochs in the first db +check(mtn("db", "set_epoch", "testbranch", "12345"), 1, false, false) +check(mtn("db", "set_epoch", "testbranch", string.rep("a", 40)), 0, false, false) +check(mtn("db", "set_epoch", "otherbranch", string.rep("a", 40)), 0, false, false) + +-- this should *fail* to sync +srv = netsync.start("testbranch") +-- This should probably expect an exit value of 1, but ATM the netsync +-- client doesn't report errors in its exit value. +-- srv:pull("testbranch", 2, 1) +srv:pull("testbranch") +srv:finish() + +check(mtn("list", "epochs"), 0, true) +check(qgrep("testbranch", "stdout")) +check(mtn2("list", "epochs"), 0, true) +check(qgrep("testbranch", "stdout")) +check_different_stdout(mtn("list", "epochs"), mtn2("list", "epochs")) + +-- confirm, we did not get the new revision +check(mtn2("automate", "get_revision", revs[1]), 1, false, false) ============================================================ --- tests/netsync_client_absorbs_server_key/__driver__.lua 0cbcb51504ad96f5bc0bc319afd59324c7864aa7 +++ tests/netsync_client_absorbs_server_key/__driver__.lua 0cbcb51504ad96f5bc0bc319afd59324c7864aa7 @@ -0,0 +1,19 @@ + +mtn_setup() +netsync.setup() + +addfile("testfile", "foo bar") +commit() + +check(mtn("genkey", "address@hidden"), 0, false, false, "address@hidden@bar\n") +check(mtn("pubkey", "address@hidden"), 0, true, false) +canonicalize("stdout") +copyfile("stdout", "foo_public") + +srv = netsync.start({"address@hidden", "testbranch"}) +srv:pull("testbranch") +srv:stop() + +check(mtn2("pubkey", "address@hidden"), 0, true, false) +canonicalize("stdout") +check(samefile("foo_public", "stdout")) ============================================================ --- tests/netsync_default_server_pattern/__driver__.lua 9d6bfba198be151bc2dea9365694d0c8af9481eb +++ tests/netsync_default_server_pattern/__driver__.lua 9d6bfba198be151bc2dea9365694d0c8af9481eb @@ -0,0 +1,41 @@ + +mtn_setup() +netsync.setup() +revs = {} + +addfile("testfile", "blah blah") +commit() +revs.testbranch = base_revision() + +writefile("testfile", "stuff stuff") +commit("otherbranch") +revs.otherbranch = base_revision() + +writefile("testfile", "nonsense nonsense") +commit("thirdbranch") +revs.thirdbranch = base_revision() + +srv = netsync.start({"testbranch", "otherbranch", "thirdbranch"}) + +-- First make sure netsync with explicit server/pattern override defaults +check(mtn2("set", "database", "default-server", "nonsense"), 0, false, false) +check(mtn2("set", "database", "default-include-pattern", "nonsense"), 0, false, false) +srv:pull("testbranch") +check(mtn2("checkout", "--branch=testbranch", "--revision", revs.testbranch, "testdir1"), 0, false, false) +check(exists("testdir1/testfile")) + +-- Now make sure explicit server with default pattern works... +check(mtn2("set", "database", "default-server", "nonsense"), 0, false, false) +check(mtn2("set", "database", "default-include-pattern", "otherbranch"), 0, false, false) +srv:pull() +check(mtn2("checkout", "--branch=otherbranch", "--revision", revs.otherbranch, "testdir2"), 0, false, false) +check(exists("testdir2/testfile")) + +-- And finally, make sure that passing nothing at all also works (uses default) +check(mtn2("set", "database", "default-server", srv.address), 0, false, false) +check(mtn2("set", "database", "default-include-pattern", "thirdbranch"), 0, false, false) +check(mtn2("sync"), 0, false, false) +check(mtn2("checkout", "--branch=thirdbranch", "--revision", revs.thirdbranch, "testdir3"), 0, false, false) +check(exists("testdir3/testfile")) + +srv:finish() ============================================================ --- tests/netsync_default_server_pattern_setting/__driver__.lua 5e7636e39a861076f1e2ef44ab71b31bf09d3320 +++ tests/netsync_default_server_pattern_setting/__driver__.lua 5e7636e39a861076f1e2ef44ab71b31bf09d3320 @@ -0,0 +1,21 @@ + +mtn_setup() +netsync.setup() + +addfile("testfile", "blah blah") +commit() + +srv = netsync.start("testbranch") +srv:pull("testbranch") + +writefile("testfile", "other stuff") +commit() +rev = base_revision() + +-- Having done an explicit pull once, future ones should default to the +-- same +check(mtn2("pull"), 0, false, false) +srv:finish() + +check(mtn2("checkout", "--revision", rev, "testdir"), 0, false, false) +check(samefile("testfile", "testdir/testfile")) ============================================================ --- tests/netsync_epochs_are_not_sent_upstream_by_pull/__driver__.lua 132cf3ec3c4a54225a1da51ec500c262bedf4dd4 +++ tests/netsync_epochs_are_not_sent_upstream_by_pull/__driver__.lua 132cf3ec3c4a54225a1da51ec500c262bedf4dd4 @@ -0,0 +1,19 @@ + +mtn_setup() +netsync.setup() + +-- This is important, because if I only have read-only access to your +-- database, I shouldn't be able to clutter it with random epochs... + +addfile("testfile", "some data") +commit() + +remove_recursive("_MTN") +check(mtn2("setup", "--branch=testbranch", ".")) +writefile("otherfile", "some data") +check(mtn2("add", "testfile"), 0, false, false) +check(mtn2("commit", "--message=foo", "--branch=testbranch.subbranch"), 0, false, false) + +netsync.pull("testbranch.*") + +check_different_stdout{"list", "epochs"} ============================================================ --- tests/netsync_is_not_interrupted_by_SIGPIPE/__driver__.lua 39bccb461318f1b4c5a989cc8216416dcffe4d85 +++ tests/netsync_is_not_interrupted_by_SIGPIPE/__driver__.lua 39bccb461318f1b4c5a989cc8216416dcffe4d85 @@ -0,0 +1,25 @@ + +skip_if(ostype == "Windows") +mtn_setup() +netsync.setup() + +function netsync_killpipe(obj) + kill(obj.pid, 13) +end + +writefile("testfile", "version 0 of test file") +check(mtn("add", "testfile"), 0, false, false) +commit() + +writefile("testfile", "version 1 of test file") +commit() + +srv = netsync.start("testbranch") + +-- send the server a SIGPIPE signal (it should survive) +netsync_killpipe(srv) + +-- this will fail if the SIGPIPE terminated it +srv:pull("testbranch") + +srv:stop() ============================================================ --- tests/netsync_server_absorbs_and_checks_epochs/__driver__.lua cd53ea129784c1c830ac8e46e8118f6432ce713a +++ tests/netsync_server_absorbs_and_checks_epochs/__driver__.lua cd53ea129784c1c830ac8e46e8118f6432ce713a @@ -0,0 +1,56 @@ + +mtn_setup() +netsync.setup() +revs = {} + +writefile("testfile", "some data") +check(mtn2("add", "testfile"), 0, false, false) +check(mtn2("commit", "--message=foo", "--branch=testbranch"), 0, false, false) +revs[0] = base_revision() + +netsync.push("testbranch") + +-- check that the first db got our epoch +check_same_stdout{"list", "epochs"} + +-- check that epochs are only sent for netsync'ed branches +check(mtn("list", "epochs"), 0, true, false) +rename("stdout", "orig-epochs") +writefile("otherfile", "other data") +check(mtn2("add", "otherfile"), 0, false, false) +check(mtn2("commit", "--message=foo", "--branch=otherbranch"), 0, false, false) +-- Run an irrelevant netsync, just to force epochs to be regenerated +srv = netsync.start("otherbranch", 2) +srv:sync("otherbranch", 3) +srv:finish() +-- Run the real netsync +netsync.push("testbranch") +check(mtn("list", "epochs"), 0, true, false) +rename("stdout", "new-epochs") +check(samefile("orig-epochs", "new-epochs")) +check_different_stdout{"list", "epochs"} + +writefile("testfile", "new version of data") +check(mtn2("commit", "--message=foo", "--branch=testbranch"), 0, false, false) +revs[1] = base_revision() + +-- change the epochs in the second db +check(mtn("db", "set_epoch", "testbranch", string.rep("a", 40)), 0, false, false) +check(mtn("db", "set_epoch", "otherbranch", string.rep("a", 40)), 0, false, false) + +-- this should *fail* to sync +srv = netsync.start("testbranch") +-- This should probably expect an exit value of 1, but ATM the netsync +-- client doesn't report errors in its exit value. +-- srv:pull("testbranch", 2, 1) +srv:pull("testbranch") +srv:finish() + +check(mtn("list", "epochs"), 0, true) +check(qgrep("testbranch", "stdout")) +check(mtn2("list", "epochs"), 0, true) +check(qgrep("testbranch", "stdout")) +check_different_stdout{"list", "epochs"} + +-- confirm, we did not get the new revision +check(mtn("automate", "get_revision", revs[1]), 1, false, false) ============================================================ --- tests/netsync_verifies_server_keys/__driver__.lua 3784142a3b85cfc0a791a2ea42045b4e35c40024 +++ tests/netsync_verifies_server_keys/__driver__.lua 3784142a3b85cfc0a791a2ea42045b4e35c40024 @@ -0,0 +1,30 @@ + +mtn_setup() +netsync.setup() + +check(mtn("genkey", "address@hidden"), 0, false, false, "address@hidden@bar\n") + +-- Once to let the client note down the key... +-- We need to set the random seed, because each time a server is +-- started it picks a new random port. +seed = os.time() +math.randomseed(seed) +netsync.pull("testbranch") + +-- Then again with a different key; should fail. +math.randomseed(seed) +srv = netsync.start{"address@hidden", "testbranch"} + +srv:pull("testbranch", nil, 1) +-- It shouldn't have absorbed the key, either. +check(mtn2("pubkey", "address@hidden"), 1, true, false) + +-- But if we then clear the client's known_hosts entry, it should be fine +check(mtn2("unset", "known-servers", srv.address), 0, false, false) + +-- Now it should succeed +srv:pull("testbranch") +-- And have absorbed the key +check(mtn2("pubkey", "address@hidden"), 0, true, false) + +srv:stop() ============================================================ --- tests/rename_moves_attributes/__driver__.lua 1c100548abe65110e89fa57d7a271abd1a65f904 +++ tests/rename_moves_attributes/__driver__.lua 1c100548abe65110e89fa57d7a271abd1a65f904 @@ -0,0 +1,23 @@ + +mtn_setup() + +addfile("testfile", "foo bar") +check(mtn("attr", "set", "testfile", "some_key", "some_value"), 0, false, false) +check(mtn("attr", "get", "testfile"), 0, true, false) +check(qgrep("some_key", "stdout")) +check(qgrep("some_value", "stdout")) + +commit() + +check(mtn("rename", "testfile", "otherfile"), 0, false, false) +rename("testfile", "otherfile") +commit() + +-- Create a new testfile, so 'attr get' has a chance to succeed +addfile("testfile", "thing stuff") +check(mtn("attr", "get", "testfile"), 0, true, false) +check(not qgrep("some_key", "stdout")) +check(not qgrep("some_value", "stdout")) +check(mtn("attr", "get", "otherfile"), 0, true, false) +check(qgrep("some_key", "stdout")) +check(qgrep("some_value", "stdout")) ============================================================ --- tests/setup_creates__MTN_log/__driver__.lua 315fa7b0899ae36ead61b25da7a98ee8c543c87e +++ tests/setup_creates__MTN_log/__driver__.lua 315fa7b0899ae36ead61b25da7a98ee8c543c87e @@ -0,0 +1,5 @@ + +mtn_setup() + +check(exists("_MTN/log")) +check(fsize("_MTN/log") == 0) ============================================================ --- tests/short_options_work_correctly/__driver__.lua 42d40c67ca2f855414d90caf721881601cbc01f6 +++ tests/short_options_work_correctly/__driver__.lua 42d40c67ca2f855414d90caf721881601cbc01f6 @@ -0,0 +1,29 @@ +-- -*- Autoconf -*- + +-- a test for the abbreviate options (-b, -k, -r, -m) + +mtn_setup() + +writefile("maude", "the file maude") + +writefile("liver", "the file liver") + +-- same as mtn() but without --db and --key +function short_mtn(...) + return raw_mtn("--rcfile", test_root.."/test_hooks.lua", + "--nostd", "--norc", "--root", test_root, + "--keydir", test_root.."/keys", unpack(arg)) +end + +check(short_mtn("add", "maude"), 0, false, false) + +-- check it won't work with a bad key +check(short_mtn("-k", "address@hidden", "-b", "test.branch", "commit", + "-d", "test.db", "-m", "happy"), 1, false, false) + +-- the failed log will have been saved +remove("_MTN/log") + +-- and it does work with a key +check(short_mtn("-k", "address@hidden", "-b", "test.branch", "commit", + "-d", "test.db", "-m", "happy"), 0, false, false) ============================================================ --- tests/test_a_merge_5/__driver__.lua 0f0e4d7042ceb2fe560c0e8b082bbaabc265e61c +++ tests/test_a_merge_5/__driver__.lua 0f0e4d7042ceb2fe560c0e8b082bbaabc265e61c @@ -0,0 +1,46 @@ + +mtn_setup() + +-- This test is a bug report. + +-- Another real merge error. This is the diff between the correct +-- result and the file produced by the merge: +-- +-- --- correct +-- +++ testfile +-- @@ -99,6 +99,8 @@ +-- +-- void get_ids(std::string const & table, std::set< hexenc > & ids); +-- +-- + void get_ids(std::string const & table, std::set< hexenc > & ids); +-- + +-- void get(hexenc const & new_id, +-- base64< gzip > & dat, +-- std::string const & table); + +-- This seems to be a really nasty testcase somehow. monotone and +-- merge(1) give identical, incorrect output. diff3(1) reports a +-- conflict. xxdiff merges cleanly, and, AFAICT, correctly. + +getfile("parent") +getfile("left") +getfile("right") +getfile("correct") + +copyfile("parent", "testfile") +check(mtn("add", "testfile"), 0, false, false) +commit() +parent = base_revision() + +copyfile("left", "testfile") +commit() + +revert_to(parent) + +copyfile("right", "testfile") +commit() + +check(mtn("--branch=testbranch", "merge"), 0, false, false) + +check(mtn("update"), 0, false, false) +xfail_if(true, samefile("testfile", "correct")) ============================================================ --- tests/test_a_merge_5/correct 5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b +++ tests/test_a_merge_5/correct 5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b @@ -0,0 +1,427 @@ +#ifndef __DATABASE_HH__ +#define __DATABASE_HH__ + +// copyright (C) 2002, 2003 graydon hoare +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +struct sqlite3; +struct cert; + +#include +#include +#include +#include + +#include + +#include "commands.hh" +#include "manifest.hh" +#include "numeric_vocab.hh" +#include "vocab.hh" + +struct revision_set; + +// this file defines a public, typed interface to the database. +// the database class encapsulates all knowledge about sqlite, +// the schema, and all SQL statements used to access the schema. +// +// one thing which is rather important to note is that this file +// deals with two sorts of version relationships. the versions +// stored in the database are all *backwards* from those the program +// sees. so for example if you have two versions of a file +// +// file.1, file.2 +// +// where file.2 was a modification of file.1, then as far as the rest of +// the application is concerned -- and the ancestry graph -- file.1 is the +// "old" version and file.2 is the "new" version. note the use of terms +// which describe time, and the sequence of edits a user makes to a +// file. those are ancestry terms. when the application composes a +// patchset, for example, it'll contain the diff delta(file.1, file.2) +// +// from the database's perspective, however, file.1 is the derived version, +// and file.2 is the base version. the base version is stored in the +// "files" table, and the *reverse* diff delta(file.2, file.1) is stored in +// the "file_deltas" table, under the id of file.1, with the id of file.2 +// listed as its base. note the use of the terms which describe +// reconstruction; those are storage-system terms. +// +// the interface *to* the database, and the ancestry version graphs, use +// the old / new metaphor of ancestry, but within the database (including +// the private helper methods, and the storage version graphs) the +// base/derived storage metaphor is used. the only real way to tell which +// is which is to look at the parameter names and code. I might try to +// express this in the type system some day, but not presently. +// +// the key phrase to keep repeating when working on this code is: +// +// "base files are new, derived files are old" +// +// it makes the code confusing, I know. this is possibly the worst part of +// the program. I don't know if there's any way to make it clearer. + +class transaction_guard; +struct posting; +struct app_state; + +class database +{ + fs::path filename; + std::string const schema; + void check_schema(); + + struct app_state * __app; + struct sqlite3 * __sql; + struct sqlite3 * sql(bool init = false); + int transaction_level; + + void install_functions(app_state * app); + void install_views(); + + typedef std::vector< std::vector > results; + void execute(char const * query, ...); + void fetch(results & res, + int const want_cols, + int const want_rows, + char const * query, ...); + + bool exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + hexenc const & base, + std::string const & table); + + unsigned long count(std::string const & table); + + void get_ids(std::string const & table, std::set< hexenc > & ids); + + void get(hexenc const & new_id, + base64< gzip > & dat, + std::string const & table); + void get_delta(hexenc const & ident, + hexenc const & base, + base64< gzip > & del, + std::string const & table); + void get_version(hexenc const & id, + base64< gzip > & dat, + std::string const & data_table, + std::string const & delta_table); + + void put(hexenc const & new_id, + base64< gzip > const & dat, + std::string const & table); + void drop(hexenc const & base, + std::string const & table); + void put_delta(hexenc const & id, + hexenc const & base, + base64< gzip > const & del, + std::string const & table); + void put_version(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + std::string const & data_table, + std::string const & delta_table); + void put_reverse_version(hexenc const & new_id, + hexenc const & old_id, + base64< gzip > const & reverse_del, + std::string const & data_table, + std::string const & delta_table); + + void get_keys(std::string const & table, std::vector & keys); + + bool cert_exists(cert const & t, + std::string const & table); + void put_cert(cert const & t, std::string const & table); + void results_to_certs(results const & res, + std::vector & certs); + + void get_certs(std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + base64 const & val, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + base64 const & val, + std::vector & certs, + std::string const & table); + + void begin_transaction(); + void commit_transaction(); + void rollback_transaction(); + friend class transaction_guard; + friend void rcs_put_raw_file_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + friend void rcs_put_raw_manifest_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + +public: + + database(fs::path const & file); + + void set_filename(fs::path const & file); + void initialize(); + void debug(std::string const & sql, std::ostream & out); + void dump(std::ostream &); + void load(std::istream &); + void info(std::ostream &); + void version(std::ostream &); + void migrate(); + void rehash(); + void ensure_open(); + + bool file_version_exists(file_id const & id); + bool manifest_version_exists(manifest_id const & id); + bool revision_exists(revision_id const & id); + + void get_file_ids(std::set & ids); + void get_manifest_ids(std::set & ids); + void get_revision_ids(std::set & ids); + + void set_app(app_state * app); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist) + void get_file_version(file_id const & id, + file_data & dat); + + // get file delta if it exists, else calculate it. + // both manifests must exist. + void get_file_delta(file_id const & src, + file_id const & dst, + file_delta & del); + + // put file w/o predecessor into db + void put_file(file_id const & new_id, + file_data const & dat); + + // store new version and update old version to be a delta + void put_file_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_file_reverse_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist). + void get_manifest_version(manifest_id const & id, + manifest_data & dat); + + // get a constructed manifest + void get_manifest(manifest_id const & id, + manifest_map & mm); + + // get manifest delta if it exists, else calculate it. + // both manifests must exist. + void get_manifest_delta(manifest_id const & src, + manifest_id const & dst, + manifest_delta & del); + + // put manifest w/o predecessor into db + void put_manifest(manifest_id const & new_id, + manifest_data const & dat); + + // store new version and update old version to be a delta + void put_manifest_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_manifest_reverse_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + + void get_revision_ancestry(std::multimap & graph); + + void get_revision_parents(revision_id const & id, + std::set & parents); + + void get_revision_children(revision_id const & id, + std::set & children); + + void get_revision_manifest(revision_id const & cid, + manifest_id & mid); + + void get_revision(revision_id const & id, + revision_set & cs); + + void get_revision(revision_id const & id, + revision_data & dat); + + void put_revision(revision_id const & new_id, + revision_set const & cs); + + void put_revision(revision_id const & new_id, + revision_data const & dat); + + void delete_existing_revs_and_certs(); + + // crypto key / cert operations + + void get_key_ids(std::string const & pattern, + std::vector & pubkeys, + std::vector & privkeys); + + void get_private_keys(std::vector & privkeys); + void get_public_keys(std::vector & pubkeys); + + bool key_exists(rsa_keypair_id const & id); + + bool public_key_exists(hexenc const & hash); + bool public_key_exists(rsa_keypair_id const & id); + bool private_key_exists(rsa_keypair_id const & id); + + void get_pubkey(hexenc const & hash, + rsa_keypair_id & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64< arc4 > & priv_encoded); + + void put_key(rsa_keypair_id const & id, + base64 const & pub_encoded); + + void put_key(rsa_keypair_id const & id, + base64< arc4 > const & priv_encoded); + + void put_key_pair(rsa_keypair_id const & pub_id, + base64 const & pub_encoded, + base64< arc4 > const & priv_encoded); + + void delete_private_key(rsa_keypair_id const & pub_id); + + // note: this section is ridiculous. please do something about it. + + bool manifest_cert_exists(manifest const & cert); + bool manifest_cert_exists(hexenc const & hash); + void put_manifest_cert(manifest const & cert); + + bool revision_cert_exists(revision const & cert); + bool revision_cert_exists(hexenc const & hash); + + void put_revision_cert(revision const & cert); + + // this variant has to be rather coarse and fast, for netsync's use + void get_revision_cert_index(std::vector< std::pair, + std::pair > > & idx); + + void get_revision_certs(std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + base64 const & val, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + base64 const & value, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + std::vector< revision > & certs); + + void get_revision_cert(hexenc const & hash, + revision & cert); + + void get_manifest_certs(manifest_id const & id, + std::vector< manifest > & certs); + + void get_manifest_certs(cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_certs(manifest_id const & id, + cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_cert(hexenc const & hash, + manifest & cert); + + // epochs + + void get_epochs(std::map & epochs); + + void get_epoch(epoch_id const & eid, cert_value & branch, epoch_data & epo); + + bool epoch_exists(epoch_id const & eid); + + void set_epoch(cert_value const & branch, epoch_data const & epo); + + void clear_epoch(cert_value const & branch); + + // completion stuff + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(commands::selector_type ty, + std::string const & partial, + std::vector > const & limit, + std::set & completions); + + ~database(); + +}; + +// transaction guards nest. acquire one in any scope you'd like +// transaction-protected, and it'll make sure the db aborts a +// txn if there's any exception before you call commit() + +class transaction_guard +{ + bool committed; + database & db; +public: + transaction_guard(database & d); + ~transaction_guard(); + void commit(); +}; + + + +#endif // __DATABASE_HH__ ============================================================ --- tests/test_a_merge_5/left 5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b +++ tests/test_a_merge_5/left 5710bd5dfa7312c757e292ecf8a9e77b9ec93b5b @@ -0,0 +1,427 @@ +#ifndef __DATABASE_HH__ +#define __DATABASE_HH__ + +// copyright (C) 2002, 2003 graydon hoare +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +struct sqlite3; +struct cert; + +#include +#include +#include +#include + +#include + +#include "commands.hh" +#include "manifest.hh" +#include "numeric_vocab.hh" +#include "vocab.hh" + +struct revision_set; + +// this file defines a public, typed interface to the database. +// the database class encapsulates all knowledge about sqlite, +// the schema, and all SQL statements used to access the schema. +// +// one thing which is rather important to note is that this file +// deals with two sorts of version relationships. the versions +// stored in the database are all *backwards* from those the program +// sees. so for example if you have two versions of a file +// +// file.1, file.2 +// +// where file.2 was a modification of file.1, then as far as the rest of +// the application is concerned -- and the ancestry graph -- file.1 is the +// "old" version and file.2 is the "new" version. note the use of terms +// which describe time, and the sequence of edits a user makes to a +// file. those are ancestry terms. when the application composes a +// patchset, for example, it'll contain the diff delta(file.1, file.2) +// +// from the database's perspective, however, file.1 is the derived version, +// and file.2 is the base version. the base version is stored in the +// "files" table, and the *reverse* diff delta(file.2, file.1) is stored in +// the "file_deltas" table, under the id of file.1, with the id of file.2 +// listed as its base. note the use of the terms which describe +// reconstruction; those are storage-system terms. +// +// the interface *to* the database, and the ancestry version graphs, use +// the old / new metaphor of ancestry, but within the database (including +// the private helper methods, and the storage version graphs) the +// base/derived storage metaphor is used. the only real way to tell which +// is which is to look at the parameter names and code. I might try to +// express this in the type system some day, but not presently. +// +// the key phrase to keep repeating when working on this code is: +// +// "base files are new, derived files are old" +// +// it makes the code confusing, I know. this is possibly the worst part of +// the program. I don't know if there's any way to make it clearer. + +class transaction_guard; +struct posting; +struct app_state; + +class database +{ + fs::path filename; + std::string const schema; + void check_schema(); + + struct app_state * __app; + struct sqlite3 * __sql; + struct sqlite3 * sql(bool init = false); + int transaction_level; + + void install_functions(app_state * app); + void install_views(); + + typedef std::vector< std::vector > results; + void execute(char const * query, ...); + void fetch(results & res, + int const want_cols, + int const want_rows, + char const * query, ...); + + bool exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + hexenc const & base, + std::string const & table); + + unsigned long count(std::string const & table); + + void get_ids(std::string const & table, std::set< hexenc > & ids); + + void get(hexenc const & new_id, + base64< gzip > & dat, + std::string const & table); + void get_delta(hexenc const & ident, + hexenc const & base, + base64< gzip > & del, + std::string const & table); + void get_version(hexenc const & id, + base64< gzip > & dat, + std::string const & data_table, + std::string const & delta_table); + + void put(hexenc const & new_id, + base64< gzip > const & dat, + std::string const & table); + void drop(hexenc const & base, + std::string const & table); + void put_delta(hexenc const & id, + hexenc const & base, + base64< gzip > const & del, + std::string const & table); + void put_version(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + std::string const & data_table, + std::string const & delta_table); + void put_reverse_version(hexenc const & new_id, + hexenc const & old_id, + base64< gzip > const & reverse_del, + std::string const & data_table, + std::string const & delta_table); + + void get_keys(std::string const & table, std::vector & keys); + + bool cert_exists(cert const & t, + std::string const & table); + void put_cert(cert const & t, std::string const & table); + void results_to_certs(results const & res, + std::vector & certs); + + void get_certs(std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + base64 const & val, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + base64 const & val, + std::vector & certs, + std::string const & table); + + void begin_transaction(); + void commit_transaction(); + void rollback_transaction(); + friend class transaction_guard; + friend void rcs_put_raw_file_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + friend void rcs_put_raw_manifest_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + +public: + + database(fs::path const & file); + + void set_filename(fs::path const & file); + void initialize(); + void debug(std::string const & sql, std::ostream & out); + void dump(std::ostream &); + void load(std::istream &); + void info(std::ostream &); + void version(std::ostream &); + void migrate(); + void rehash(); + void ensure_open(); + + bool file_version_exists(file_id const & id); + bool manifest_version_exists(manifest_id const & id); + bool revision_exists(revision_id const & id); + + void get_file_ids(std::set & ids); + void get_manifest_ids(std::set & ids); + void get_revision_ids(std::set & ids); + + void set_app(app_state * app); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist) + void get_file_version(file_id const & id, + file_data & dat); + + // get file delta if it exists, else calculate it. + // both manifests must exist. + void get_file_delta(file_id const & src, + file_id const & dst, + file_delta & del); + + // put file w/o predecessor into db + void put_file(file_id const & new_id, + file_data const & dat); + + // store new version and update old version to be a delta + void put_file_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_file_reverse_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist). + void get_manifest_version(manifest_id const & id, + manifest_data & dat); + + // get a constructed manifest + void get_manifest(manifest_id const & id, + manifest_map & mm); + + // get manifest delta if it exists, else calculate it. + // both manifests must exist. + void get_manifest_delta(manifest_id const & src, + manifest_id const & dst, + manifest_delta & del); + + // put manifest w/o predecessor into db + void put_manifest(manifest_id const & new_id, + manifest_data const & dat); + + // store new version and update old version to be a delta + void put_manifest_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_manifest_reverse_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + + void get_revision_ancestry(std::multimap & graph); + + void get_revision_parents(revision_id const & id, + std::set & parents); + + void get_revision_children(revision_id const & id, + std::set & children); + + void get_revision_manifest(revision_id const & cid, + manifest_id & mid); + + void get_revision(revision_id const & id, + revision_set & cs); + + void get_revision(revision_id const & id, + revision_data & dat); + + void put_revision(revision_id const & new_id, + revision_set const & cs); + + void put_revision(revision_id const & new_id, + revision_data const & dat); + + void delete_existing_revs_and_certs(); + + // crypto key / cert operations + + void get_key_ids(std::string const & pattern, + std::vector & pubkeys, + std::vector & privkeys); + + void get_private_keys(std::vector & privkeys); + void get_public_keys(std::vector & pubkeys); + + bool key_exists(rsa_keypair_id const & id); + + bool public_key_exists(hexenc const & hash); + bool public_key_exists(rsa_keypair_id const & id); + bool private_key_exists(rsa_keypair_id const & id); + + void get_pubkey(hexenc const & hash, + rsa_keypair_id & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64< arc4 > & priv_encoded); + + void put_key(rsa_keypair_id const & id, + base64 const & pub_encoded); + + void put_key(rsa_keypair_id const & id, + base64< arc4 > const & priv_encoded); + + void put_key_pair(rsa_keypair_id const & pub_id, + base64 const & pub_encoded, + base64< arc4 > const & priv_encoded); + + void delete_private_key(rsa_keypair_id const & pub_id); + + // note: this section is ridiculous. please do something about it. + + bool manifest_cert_exists(manifest const & cert); + bool manifest_cert_exists(hexenc const & hash); + void put_manifest_cert(manifest const & cert); + + bool revision_cert_exists(revision const & cert); + bool revision_cert_exists(hexenc const & hash); + + void put_revision_cert(revision const & cert); + + // this variant has to be rather coarse and fast, for netsync's use + void get_revision_cert_index(std::vector< std::pair, + std::pair > > & idx); + + void get_revision_certs(std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + base64 const & val, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + base64 const & value, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + std::vector< revision > & certs); + + void get_revision_cert(hexenc const & hash, + revision & cert); + + void get_manifest_certs(manifest_id const & id, + std::vector< manifest > & certs); + + void get_manifest_certs(cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_certs(manifest_id const & id, + cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_cert(hexenc const & hash, + manifest & cert); + + // epochs + + void get_epochs(std::map & epochs); + + void get_epoch(epoch_id const & eid, cert_value & branch, epoch_data & epo); + + bool epoch_exists(epoch_id const & eid); + + void set_epoch(cert_value const & branch, epoch_data const & epo); + + void clear_epoch(cert_value const & branch); + + // completion stuff + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(commands::selector_type ty, + std::string const & partial, + std::vector > const & limit, + std::set & completions); + + ~database(); + +}; + +// transaction guards nest. acquire one in any scope you'd like +// transaction-protected, and it'll make sure the db aborts a +// txn if there's any exception before you call commit() + +class transaction_guard +{ + bool committed; + database & db; +public: + transaction_guard(database & d); + ~transaction_guard(); + void commit(); +}; + + + +#endif // __DATABASE_HH__ ============================================================ --- tests/test_a_merge_5/parent abd633b6089b43c3097b08ab5c44a9b1d40472eb +++ tests/test_a_merge_5/parent abd633b6089b43c3097b08ab5c44a9b1d40472eb @@ -0,0 +1,423 @@ +#ifndef __DATABASE_HH__ +#define __DATABASE_HH__ + +// copyright (C) 2002, 2003 graydon hoare +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +struct sqlite3; +struct cert; + +#include +#include +#include + +#include + +#include "commands.hh" +#include "manifest.hh" +#include "numeric_vocab.hh" +#include "vocab.hh" + +struct revision_set; + +// this file defines a public, typed interface to the database. +// the database class encapsulates all knowledge about sqlite, +// the schema, and all SQL statements used to access the schema. +// +// one thing which is rather important to note is that this file +// deals with two sorts of version relationships. the versions +// stored in the database are all *backwards* from those the program +// sees. so for example if you have two versions of a file +// +// file.1, file.2 +// +// where file.2 was a modification of file.1, then as far as the rest of +// the application is concerned -- and the ancestry graph -- file.1 is the +// "old" version and file.2 is the "new" version. note the use of terms +// which describe time, and the sequence of edits a user makes to a +// file. those are ancestry terms. when the application composes a +// patchset, for example, it'll contain the diff delta(file.1, file.2) +// +// from the database's perspective, however, file.1 is the derived version, +// and file.2 is the base version. the base version is stored in the +// "files" table, and the *reverse* diff delta(file.2, file.1) is stored in +// the "file_deltas" table, under the id of file.1, with the id of file.2 +// listed as its base. note the use of the terms which describe +// reconstruction; those are storage-system terms. +// +// the interface *to* the database, and the ancestry version graphs, use +// the old / new metaphor of ancestry, but within the database (including +// the private helper methods, and the storage version graphs) the +// base/derived storage metaphor is used. the only real way to tell which +// is which is to look at the parameter names and code. I might try to +// express this in the type system some day, but not presently. +// +// the key phrase to keep repeating when working on this code is: +// +// "base files are new, derived files are old" +// +// it makes the code confusing, I know. this is possibly the worst part of +// the program. I don't know if there's any way to make it clearer. + +class transaction_guard; +struct posting; +struct app_state; + +class database +{ + fs::path filename; + std::string const schema; + void check_schema(); + + struct app_state * __app; + struct sqlite3 * __sql; + struct sqlite3 * sql(bool init = false); + int transaction_level; + + void install_functions(app_state * app); + void install_views(); + + typedef std::vector< std::vector > results; + void execute(char const * query, ...); + void fetch(results & res, + int const want_cols, + int const want_rows, + char const * query, ...); + + bool exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + hexenc const & base, + std::string const & table); + + int count(std::string const & table); + + void get(hexenc const & new_id, + base64< gzip > & dat, + std::string const & table); + void get_delta(hexenc const & ident, + hexenc const & base, + base64< gzip > & del, + std::string const & table); + void get_version(hexenc const & id, + base64< gzip > & dat, + std::string const & data_table, + std::string const & delta_table); + + void put(hexenc const & new_id, + base64< gzip > const & dat, + std::string const & table); + void drop(hexenc const & base, + std::string const & table); + void put_delta(hexenc const & id, + hexenc const & base, + base64< gzip > const & del, + std::string const & table); + void put_version(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + std::string const & data_table, + std::string const & delta_table); + void put_reverse_version(hexenc const & new_id, + hexenc const & old_id, + base64< gzip > const & reverse_del, + std::string const & data_table, + std::string const & delta_table); + + bool cert_exists(cert const & t, + std::string const & table); + void put_cert(cert const & t, std::string const & table); + void results_to_certs(results const & res, + std::vector & certs); + + void get_certs(hexenc const & id, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + base64 const & val, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + base64 const & val, + std::vector & certs, + std::string const & table); + + void begin_transaction(); + void commit_transaction(); + void rollback_transaction(); + friend class transaction_guard; + friend void rcs_put_raw_file_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + friend void rcs_put_raw_manifest_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + +public: + + database(fs::path const & file); + + unsigned long get_statistic(std::string const & query); + void set_filename(fs::path const & file); + void initialize(); + void debug(std::string const & sql, std::ostream & out); + void dump(std::ostream &); + void load(std::istream &); + void info(std::ostream &); + void version(std::ostream &); + void migrate(); + void rehash(); + void ensure_open(); + + bool file_version_exists(file_id const & id); + bool manifest_version_exists(manifest_id const & id); + bool revision_exists(revision_id const & id); + void set_app(app_state * app); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist) + void get_file_version(file_id const & id, + file_data & dat); + + // get file delta if it exists, else calculate it. + // both manifests must exist. + void get_file_delta(file_id const & src, + file_id const & dst, + file_delta & del); + + // put file w/o predecessor into db + void put_file(file_id const & new_id, + file_data const & dat); + + // store new version and update old version to be a delta + void put_file_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_file_reverse_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist). + void get_manifest_version(manifest_id const & id, + manifest_data & dat); + + // get a constructed manifest + void get_manifest(manifest_id const & id, + manifest_map & mm); + + // get manifest delta if it exists, else calculate it. + // both manifests must exist. + void get_manifest_delta(manifest_id const & src, + manifest_id const & dst, + manifest_delta & del); + + // put manifest w/o predecessor into db + void put_manifest(manifest_id const & new_id, + manifest_data const & dat); + + // store new version and update old version to be a delta + void put_manifest_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_manifest_reverse_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + + void get_revision_ancestry(std::multimap & graph); + + void get_revision_parents(revision_id const & id, + std::set & parents); + + void get_revision_children(revision_id const & id, + std::set & children); + + void get_revision_manifest(revision_id const & cid, + manifest_id & mid); + + void get_revision(revision_id const & id, + revision_set & cs); + + void get_revision(revision_id const & id, + revision_data & dat); + + void put_revision(revision_id const & new_id, + revision_set const & cs); + + void put_revision(revision_id const & new_id, + revision_data const & dat); + + void delete_existing_revs_and_certs(); + + // crypto key / cert operations + + void get_key_ids(std::string const & pattern, + std::vector & pubkeys, + std::vector & privkeys); + + void get_private_keys(std::vector & privkeys); + + bool key_exists(rsa_keypair_id const & id); + + bool public_key_exists(hexenc const & hash); + bool public_key_exists(rsa_keypair_id const & id); + bool private_key_exists(rsa_keypair_id const & id); + + void get_pubkey(hexenc const & hash, + rsa_keypair_id & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64< arc4 > & priv_encoded); + + void put_key(rsa_keypair_id const & id, + base64 const & pub_encoded); + + void put_key(rsa_keypair_id const & id, + base64< arc4 > const & priv_encoded); + + void put_key_pair(rsa_keypair_id const & pub_id, + base64 const & pub_encoded, + base64< arc4 > const & priv_encoded); + + void delete_private_key(rsa_keypair_id const & pub_id); + + // note: this section is ridiculous. please do something about it. + + bool manifest_cert_exists(manifest const & cert); + bool manifest_cert_exists(hexenc const & hash); + void put_manifest_cert(manifest const & cert); + + bool revision_cert_exists(revision const & cert); + bool revision_cert_exists(hexenc const & hash); + + void put_revision_cert(revision const & cert); + + // this variant has to be rather coarse and fast, for netsync's use + void get_revision_cert_index(std::vector< std::pair, + std::pair > > & idx); + + void get_revision_certs(cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + base64 const & val, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + base64 const & value, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + std::vector< revision > & certs); + + void get_revision_cert(hexenc const & hash, + revision & cert); + + void get_manifest_certs(manifest_id const & id, + std::vector< manifest > & certs); + + void get_manifest_certs(cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_certs(manifest_id const & id, + cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_cert(hexenc const & hash, + manifest & cert); + + + // merkle tree stuff + + bool merkle_node_exists(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix); + + void get_merkle_node(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix, + base64 & node); + + void put_merkle_node(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix, + base64 const & node); + + void erase_merkle_nodes(std::string const & type, + utf8 const & collection); + + // completion stuff + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(commands::selector_type ty, + std::string const & partial, + std::vector > const & limit, + std::set & completions); + + ~database(); + +}; + +// transaction guards nest. acquire one in any scope you'd like +// transaction-protected, and it'll make sure the db aborts a +// txn if there's any exception before you call commit() + +class transaction_guard +{ + bool committed; + database & db; +public: + transaction_guard(database & d); + ~transaction_guard(); + void commit(); +}; + + + +#endif // __DATABASE_HH__ ============================================================ --- tests/test_a_merge_5/right 8bc1e710ca85316767395910c1e6afd03fdd9c6c +++ tests/test_a_merge_5/right 8bc1e710ca85316767395910c1e6afd03fdd9c6c @@ -0,0 +1,430 @@ +#ifndef __DATABASE_HH__ +#define __DATABASE_HH__ + +// copyright (C) 2002, 2003 graydon hoare +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +struct sqlite3; +struct cert; + +#include +#include +#include + +#include + +#include "commands.hh" +#include "manifest.hh" +#include "numeric_vocab.hh" +#include "vocab.hh" + +struct revision_set; + +// this file defines a public, typed interface to the database. +// the database class encapsulates all knowledge about sqlite, +// the schema, and all SQL statements used to access the schema. +// +// one thing which is rather important to note is that this file +// deals with two sorts of version relationships. the versions +// stored in the database are all *backwards* from those the program +// sees. so for example if you have two versions of a file +// +// file.1, file.2 +// +// where file.2 was a modification of file.1, then as far as the rest of +// the application is concerned -- and the ancestry graph -- file.1 is the +// "old" version and file.2 is the "new" version. note the use of terms +// which describe time, and the sequence of edits a user makes to a +// file. those are ancestry terms. when the application composes a +// patchset, for example, it'll contain the diff delta(file.1, file.2) +// +// from the database's perspective, however, file.1 is the derived version, +// and file.2 is the base version. the base version is stored in the +// "files" table, and the *reverse* diff delta(file.2, file.1) is stored in +// the "file_deltas" table, under the id of file.1, with the id of file.2 +// listed as its base. note the use of the terms which describe +// reconstruction; those are storage-system terms. +// +// the interface *to* the database, and the ancestry version graphs, use +// the old / new metaphor of ancestry, but within the database (including +// the private helper methods, and the storage version graphs) the +// base/derived storage metaphor is used. the only real way to tell which +// is which is to look at the parameter names and code. I might try to +// express this in the type system some day, but not presently. +// +// the key phrase to keep repeating when working on this code is: +// +// "base files are new, derived files are old" +// +// it makes the code confusing, I know. this is possibly the worst part of +// the program. I don't know if there's any way to make it clearer. + +class transaction_guard; +struct posting; +struct app_state; + +class database +{ + fs::path filename; + std::string const schema; + void check_schema(); + + struct app_state * __app; + struct sqlite3 * __sql; + struct sqlite3 * sql(bool init = false); + int transaction_level; + + void install_functions(app_state * app); + void install_views(); + + typedef std::vector< std::vector > results; + void execute(char const * query, ...); + void fetch(results & res, + int const want_cols, + int const want_rows, + char const * query, ...); + + bool exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + std::string const & table); + bool delta_exists(hexenc const & ident, + hexenc const & base, + std::string const & table); + + int count(std::string const & table); + + void get_ids(std::string const & table, std::set< hexenc > & ids); + + void get(hexenc const & new_id, + base64< gzip > & dat, + std::string const & table); + void get_delta(hexenc const & ident, + hexenc const & base, + base64< gzip > & del, + std::string const & table); + void get_version(hexenc const & id, + base64< gzip > & dat, + std::string const & data_table, + std::string const & delta_table); + + void put(hexenc const & new_id, + base64< gzip > const & dat, + std::string const & table); + void drop(hexenc const & base, + std::string const & table); + void put_delta(hexenc const & id, + hexenc const & base, + base64< gzip > const & del, + std::string const & table); + void put_version(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + std::string const & data_table, + std::string const & delta_table); + void put_reverse_version(hexenc const & new_id, + hexenc const & old_id, + base64< gzip > const & reverse_del, + std::string const & data_table, + std::string const & delta_table); + + bool cert_exists(cert const & t, + std::string const & table); + void put_cert(cert const & t, std::string const & table); + void results_to_certs(results const & res, + std::vector & certs); + + void get_certs(hexenc const & id, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(hexenc const & id, + cert_name const & name, + base64 const & val, + std::vector< cert > & certs, + std::string const & table); + + void get_certs(cert_name const & name, + base64 const & val, + std::vector & certs, + std::string const & table); + + void begin_transaction(); + void commit_transaction(); + void rollback_transaction(); + friend class transaction_guard; + friend void rcs_put_raw_file_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + friend void rcs_put_raw_manifest_edge(hexenc const & old_id, + hexenc const & new_id, + base64< gzip > const & del, + database & db); + +public: + + database(fs::path const & file); + + unsigned long get_statistic(std::string const & query); + void set_filename(fs::path const & file); + void initialize(); + void debug(std::string const & sql, std::ostream & out); + void dump(std::ostream &); + void load(std::istream &); + void info(std::ostream &); + void version(std::ostream &); + void migrate(); + void rehash(); + void ensure_open(); + + bool file_version_exists(file_id const & id); + bool manifest_version_exists(manifest_id const & id); + bool revision_exists(revision_id const & id); + + void get_file_ids(std::set & ids); + void get_manifest_ids(std::set & ids); + void get_revision_ids(std::set & ids); + + void set_app(app_state * app); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist) + void get_file_version(file_id const & id, + file_data & dat); + + // get file delta if it exists, else calculate it. + // both manifests must exist. + void get_file_delta(file_id const & src, + file_id const & dst, + file_delta & del); + + // put file w/o predecessor into db + void put_file(file_id const & new_id, + file_data const & dat); + + // store new version and update old version to be a delta + void put_file_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_file_reverse_version(file_id const & old_id, + file_id const & new_id, + file_delta const & del); + + // get plain version if it exists, or reconstruct version + // from deltas (if they exist). + void get_manifest_version(manifest_id const & id, + manifest_data & dat); + + // get a constructed manifest + void get_manifest(manifest_id const & id, + manifest_map & mm); + + // get manifest delta if it exists, else calculate it. + // both manifests must exist. + void get_manifest_delta(manifest_id const & src, + manifest_id const & dst, + manifest_delta & del); + + // put manifest w/o predecessor into db + void put_manifest(manifest_id const & new_id, + manifest_data const & dat); + + // store new version and update old version to be a delta + void put_manifest_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + // load in a "direct" new -> old reverse edge (used during + // netsync and CVS load-in) + void put_manifest_reverse_version(manifest_id const & old_id, + manifest_id const & new_id, + manifest_delta const & del); + + + void get_revision_ancestry(std::multimap & graph); + + void get_revision_parents(revision_id const & id, + std::set & parents); + + void get_revision_children(revision_id const & id, + std::set & children); + + void get_revision_manifest(revision_id const & cid, + manifest_id & mid); + + void get_revision(revision_id const & id, + revision_set & cs); + + void get_revision(revision_id const & id, + revision_data & dat); + + void put_revision(revision_id const & new_id, + revision_set const & cs); + + void put_revision(revision_id const & new_id, + revision_data const & dat); + + void delete_existing_revs_and_certs(); + + // crypto key / cert operations + + void get_key_ids(std::string const & pattern, + std::vector & pubkeys, + std::vector & privkeys); + + void get_private_keys(std::vector & privkeys); + + bool key_exists(rsa_keypair_id const & id); + + bool public_key_exists(hexenc const & hash); + bool public_key_exists(rsa_keypair_id const & id); + bool private_key_exists(rsa_keypair_id const & id); + + void get_pubkey(hexenc const & hash, + rsa_keypair_id & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64 & pub_encoded); + + void get_key(rsa_keypair_id const & id, + base64< arc4 > & priv_encoded); + + void put_key(rsa_keypair_id const & id, + base64 const & pub_encoded); + + void put_key(rsa_keypair_id const & id, + base64< arc4 > const & priv_encoded); + + void put_key_pair(rsa_keypair_id const & pub_id, + base64 const & pub_encoded, + base64< arc4 > const & priv_encoded); + + void delete_private_key(rsa_keypair_id const & pub_id); + + // note: this section is ridiculous. please do something about it. + + bool manifest_cert_exists(manifest const & cert); + bool manifest_cert_exists(hexenc const & hash); + void put_manifest_cert(manifest const & cert); + + bool revision_cert_exists(revision const & cert); + bool revision_cert_exists(hexenc const & hash); + + void put_revision_cert(revision const & cert); + + // this variant has to be rather coarse and fast, for netsync's use + void get_revision_cert_index(std::vector< std::pair, + std::pair > > & idx); + + void get_revision_certs(cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + std::vector< revision > & certs); + + void get_revision_certs(cert_name const & name, + base64 const & val, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + cert_name const & name, + base64 const & value, + std::vector< revision > & certs); + + void get_revision_certs(revision_id const & id, + std::vector< revision > & certs); + + void get_revision_cert(hexenc const & hash, + revision & cert); + + void get_manifest_certs(manifest_id const & id, + std::vector< manifest > & certs); + + void get_manifest_certs(cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_certs(manifest_id const & id, + cert_name const & name, + std::vector< manifest > & certs); + + void get_manifest_cert(hexenc const & hash, + manifest & cert); + + + // merkle tree stuff + + bool merkle_node_exists(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix); + + void get_merkle_node(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix, + base64 & node); + + void put_merkle_node(std::string const & type, + utf8 const & collection, + size_t level, + hexenc const & prefix, + base64 const & node); + + void erase_merkle_nodes(std::string const & type, + utf8 const & collection); + + // completion stuff + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(std::string const & partial, + std::set & completions); + + void complete(commands::selector_type ty, + std::string const & partial, + std::vector > const & limit, + std::set & completions); + + ~database(); + +}; + +// transaction guards nest. acquire one in any scope you'd like +// transaction-protected, and it'll make sure the db aborts a +// txn if there's any exception before you call commit() + +class transaction_guard +{ + bool committed; + database & db; +public: + transaction_guard(database & d); + ~transaction_guard(); + void commit(); +}; + + + +#endif // __DATABASE_HH__ ============================================================ --- tests/vars/__driver__.lua 17630a0ac1fac4a75582a73063d987c6b4442502 +++ tests/vars/__driver__.lua 17630a0ac1fac4a75582a73063d987c6b4442502 @@ -0,0 +1,27 @@ + +mtn_setup() + +check(mtn("set", "domain1", "key1", "orig_value"), 0, false, false) +check(mtn("set", "domain1", "key1", "overwritten_value"), 0, false, false) +check(mtn("set", "domain1", "key2", "other_value"), 0, false, false) +check(mtn("set", "domain2", "key1", "other_domain_value"), 0, false, false) +check(mtn("set", "domain2", "key2", "yet_another_value"), 0, false, false) +check(mtn("unset", "domain2", "key2")) +check(mtn("unset", "domain2", "key2"), 1, false, false) + +-- FIXME: use a less lame output format +writefile("domain1_vars", "domain1: key1 overwritten_value\n".. + "domain1: key2 other_value\n") +writefile("domain2_vars", "domain2: key1 other_domain_value\n") +check(cat("domain1_vars", "domain2_vars"), 0, true) +rename("stdout", "all_vars") + +check(mtn("ls", "vars"), 0, true, false) +canonicalize("stdout") +check(samefile("all_vars", "stdout")) +check(mtn("ls", "vars", "domain1"), 0, true, false) +canonicalize("stdout") +check(samefile("domain1_vars", "stdout")) +check(mtn("ls", "vars", "domain2"), 0, true, false) +canonicalize("stdout") +check(samefile("domain2_vars", "stdout")) ============================================================ --- tester.cc fe9ae11945602183ddc91bb850dd5a1de4ea4525 +++ tester.cc 15f9df6af209097db87c510ca37c8c93f4a4e6e9 @@ -439,6 +439,7 @@ { // global_sanity.set_debug(); string testfile; + string firstdir; bool needhelp = false; for (int i = 1; i < argc; ++i) if (string(argv[i]) == "--help" || string(argv[i]) == "-h") @@ -449,6 +450,7 @@ testfile = file.native_file_string(); save_initial_path(); source_dir = file.branch_path(); + firstdir = fs::initial_path().native_file_string(); run_dir = fs::initial_path() / "tester_dir"; fs::create_directory(run_dir); go_to_workspace(run_dir.native_file_string()); @@ -491,6 +493,10 @@ lua_register(st, "restore_env", do_restore_env); lua_register(st, "set_env", do_set_env); lua_register(st, "timed_wait", timed_wait); + + lua_pushstring(st, "initial_dir"); + lua_pushstring(st, firstdir.c_str()); + lua_settable(st, LUA_GLOBALSINDEX); int ret = 2; try ============================================================ --- tester.lua d71188603ab47fded0896bad4d89444fe49205f0 +++ tester.lua 2d9160c79827476de8af60abde5c6f7ea0a6f822 @@ -33,6 +33,7 @@ function L(...) test_log:write(unpack(arg)) + test_log:flush() end function getsrcline() @@ -252,7 +253,7 @@ end end if bgnd == true and type(cmd[1]) == "string" then local_redir = false end - L("runcmd: ", tostring(cmd[1]), ", local_redir = ", tostring(local_redir), ", requested = ", tostring(cmd.local_redirect), "\n") + L("\nruncmd: ", tostring(cmd[1]), ", local_redir = ", tostring(local_redir), ", requested = ", tostring(cmd.local_redirect)) local redir if local_redir then files.stdin = io.open(prefix.."stdin") @@ -366,8 +367,26 @@ return {docat, unpack(arg)} end +function tail(...) + local function dotail(file, num) + if num == nil then num = 10 end + local mylines = {} + for l in io.lines(file) do + table.insert(mylines, l) + if table.getn(mylines) > num then + table.remove(mylines, 1) + end + end + for _,x in ipairs(mylines) do + files.stdout:write(x, "\n") + end + return 0 + end + return {dotail, unpack(arg)} +end + function log_file_contents(filename) - L(readfile_q(filename)) + L(readfile_q(filename), "\n") end function pre_cmd(stdin, ident) @@ -444,7 +463,8 @@ out.prefix = "ts-" .. bgid .. "-" pre_cmd(stdin, out.prefix) L("Starting background command...") - local _,pid = runcmd(torun, out.prefix, true) + local ok,pid = runcmd(torun, out.prefix, true) + if not ok then err(pid, 2) end if pid == -1 then err("Failed to start background process\n", 2) end out.pid = pid bglist[bgid] = out @@ -461,6 +481,9 @@ if obj.retval ~= nil then return end if timeout == nil then timeout = 0 end + if type(timeout) ~= "number" then + err("Bad timeout of type "..type(timeout)) + end local res obj.retval, res = timed_wait(obj.pid, timeout) if (res == -1) then @@ -476,14 +499,25 @@ L(locheader(), "checking background command from ", out.locstr, table.concat(out.cmd, " ")) post_cmd(obj.retval, out.expret, out.expout, out.experr, obj.prefix) + return true end - mt.wait = function(obj) + mt.wait = function(obj, timeout) if obj.retval ~= nil then return end - obj.retval = wait(obj.pid) + if timeout == nil then + obj.retval = wait(obj.pid) + else + local res + obj.retval, res = timed_wait(obj.pid, timeout) + if res == -1 then + obj.retval = nil + return false + end + end table.remove(bglist, obj.id) L(locheader(), "checking background command from ", out.locstr, table.concat(out.cmd, " "), "\n") post_cmd(obj.retval, out.expret, out.expout, out.experr, obj.prefix) + return true end return setmetatable(out, mt) end @@ -606,7 +640,10 @@ end end end - if not list_only then P("Running tests...\n") end + if not list_only then + logfile:write("Running on ", get_ostype(), "\n\n") + P("Running tests...\n") + end local counts = {} counts.success = 0 counts.skip = 0 ============================================================ --- testsuite.at 7ac716d85aeee1483af8a1891243a9daa3fa7a53 +++ testsuite.at 657b10b3bf7ccaa263cff9617210401fc6a5c4cd @@ -608,37 +608,6 @@ # include all the sub-tests we're going to use -m4_include(tests/t_database_check.at) -m4_include(tests/t_add_owndb.at) -m4_include(tests/t_can_execute.at) -m4_include(tests/t_diff_binary.at) -m4_include(tests/t_command_completion.at) -m4_include(tests/t_merge_rename_file_and_rename_dir.at) -m4_include(tests/t_diff_restrict.at) -m4_include(tests/t_cat_file_by_name.at) -m4_include(tests/t_epoch.at) -m4_include(tests/t_epoch_server.at) -m4_include(tests/t_epoch_unidirectional.at) -m4_include(tests/t_vars.at) -m4_include(tests/t_netsync_defaults.at) -m4_include(tests/t_netsync_set_defaults.at) -m4_include(tests/t_netsync_absorbs.at) -m4_include(tests/t_netsync_checks_server_key.at) -m4_include(tests/t_merge_5.at) -m4_include(tests/t_empty_id_completion.at) -m4_include(tests/t_empty_path.at) -m4_include(tests/t_empty_env.at) -m4_include(tests/t_short_opts.at) -m4_include(tests/t_netsync_sigpipe.at) -m4_include(tests/t_setup_creates_log.at) -m4_include(tests/t_checkout_creates_log.at) -m4_include(tests/t_commit_log_1.at) -m4_include(tests/t_commit_log_2.at) -m4_include(tests/t_commit_validate.at) -m4_include(tests/t_dropkey_1.at) -m4_include(tests/t_dropkey_2.at) -m4_include(tests/t_rename_attr.at) -m4_include(tests/t_automate_ancestors.at) m4_include(tests/t_automate_descendents.at) m4_include(tests/t_automate_erase_ancestors.at) m4_include(tests/t_automate_toposort.at) ============================================================ --- testsuite.lua f61bf454ad6bfaa304208da8de782c89e9715909 +++ testsuite.lua 3e5cb0ddb4c7e5b49f076e9fbf1d5d3c2a6cb5e9 @@ -1,7 +1,41 @@ #!./tester +ostype = string.sub(get_ostype(), 1, string.find(get_ostype(), " ")-1) + +function getpathof(exe) + local function gotit(now) + if test_log == nil then + logfile:write(exe, " found at ", now, "\n") + else + test_log:write(exe, " found at ", now, "\n") + end + return now + end + local path = os.getenv("PATH") + local char + if ostype == "Windows" then + char = ';' + else + char = ':' + end + local now = initial_dir.."/"..exe + if exists(now) then return gotit(now) end + for x in string.gfind(path, "[^"..char.."]*"..char) do + local now = string.sub(x, 0, -2).."/"..exe + if exists(now) then return gotit(now) end + end + if test_log == nil then + logfile:write("Cannot find ", exe, "\n") + else + test_log:write("Cannot find ", exe, "\n") + end + return exe +end + +monotone_path = getpathof("mtn") + function safe_mtn(...) - return {"mtn", "--norc", "--root=" .. test_root, unpack(arg)} + return {monotone_path, "--norc", "--root=" .. test_root, unpack(arg)} end -- function preexecute(x) @@ -82,6 +116,7 @@ copyfile("test.db", "test3.db") copy_recursive("keys", "keys3") getstdfile("tests/netsync.lua", "netsync.lua") + math.randomseed(os.time()) end function netsync.setup_with_notes() @@ -90,11 +125,11 @@ end function netsync.internal.client(srv, oper, pat, n, res) - if pat == "" or pat == nil then pat = "*" end if n == nil then n = 2 end - check(mtn("--rcfile=netsync.lua", "--keydir=keys"..n, - "--db=test"..n..".db", oper, srv.address, pat), - res, false, false) + args = {"--rcfile=netsync.lua", "--keydir=keys"..n, + "--db=test"..n..".db", oper, srv.address} + if pat ~= nil then table.insert(args, pat) end + check(mtn(unpack(args)), res, false, false) end function netsync.internal.pull(srv, pat, n, res) srv:client("pull", pat, n, res) end function netsync.internal.push(srv, pat, n, res) srv:client("push", pat, n, res) end @@ -117,18 +152,32 @@ 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) + if type(pat) == "string" then + table.insert(args, pat) + elseif type(pat) == "table" then + local function ins(i,x) + table.insert(args,x) + end + table.foreachi(pat, ins) + else + err("Bad pattern type "..type(pat)) end + local out = bg(fn(unpack(args)), false, false, false) out.address = addr local mt = getmetatable(out) mt.client = netsync.internal.client mt.pull = netsync.internal.pull mt.push = netsync.internal.push mt.sync = netsync.internal.sync + local mt_wait = mt.wait + mt.check = function(obj) return not mt_wait(obj, 0) end + mt.wait = nil -- using this would hang; don't allow it + -- wait for "beginning service..." + while fsize(out.prefix .. "stderr") == 0 do + sleep(1) + check(out:check()) + end + mt.stop = mt.finish return out end @@ -171,8 +220,6 @@ check(base_revision() == rev) end -ostype = string.sub(get_ostype(), 1, string.find(get_ostype(), " ")-1) - function canonicalize(filename) if ostype == "Windows" then L("Canonicalizing ", filename, "\n") @@ -217,14 +264,43 @@ end end --- maybe this one should go in tester.lua? -function check_same_stdout(cmd1, cmd2) +-- maybe these should go in tester.lua? +function do_check_same_stdout(cmd1, cmd2) check(cmd1, 0, true, false) rename_over("stdout", "stdout-first") check(cmd2, 0, true, false) rename_over("stdout", "stdout-second") check(samefile("stdout-first", "stdout-second")) end +function do_check_different_stdout(cmd1, cmd2) + check(cmd1, 0, true, false) + rename_over("stdout", "stdout-first") + check(cmd2, 0, true, false) + rename_over("stdout", "stdout-second") + check(not samefile("stdout-first", "stdout-second")) +end +function check_same_stdout(a, b, c) + if type(a) == "table" and type(b) == "table" then + return do_check_same_stdout(a, b) + elseif type(a) == "table" and type(b) == "function" and type(c) == "function" then + return do_check_same_stdout(b(unpack(a)), c(unpack(a))) + elseif type(a) == "table" and type(b) == "nil" and type(c) == "nil" then + return do_check_same_stdout(mtn(unpack(a)), mtn2(unpack(a))) + else + err("bad arguments ("..type(a)..", "..type(b)..", "..type(c)..") to check_same_stdout") + end +end +function check_different_stdout(a, b, c) + if type(a) == "table" and type(b) == "table" then + return do_check_different_stdout(a, b) + elseif type(a) == "table" and type(b) == "function" and type(c) == "function" then + return do_check_different_stdout(b(unpack(a)), c(unpack(a))) + elseif type(a) == "table" and type(b) == "nil" and type(c) == "nil" then + return do_check_different_stdout(mtn(unpack(a)), mtn2(unpack(a))) + else + err("bad arguments ("..type(a)..", "..type(b)..", "..type(c)..") to check_different_stdout") + end +end function write_large_file(name, size) local file = io.open(name, "wb") @@ -385,3 +461,34 @@ table.insert(tests, "tests/(minor)_test_a_merge_3") table.insert(tests, "tests/(minor)_test_a_merge_4") table.insert(tests, "tests/db_missing") +table.insert(tests, "tests/database_check") +table.insert(tests, "tests/(minor)_add_own_db") +table.insert(tests, "tests/can_execute_things") +table.insert(tests, "tests/diff_a_binary_file") +table.insert(tests, "tests/command_completion") +table.insert(tests, "tests/merge_rename_file_and_rename_dir") +table.insert(tests, "tests/diff_respects_restrictions") +table.insert(tests, "tests/cat_-r_REV_PATH") +table.insert(tests, "tests/netsync_client_absorbs_and_checks_epochs") +table.insert(tests, "tests/netsync_server_absorbs_and_checks_epochs") +table.insert(tests, "tests/netsync_epochs_are_not_sent_upstream_by_pull") +table.insert(tests, "tests/vars") +table.insert(tests, "tests/netsync_default_server_pattern") +table.insert(tests, "tests/netsync_default_server_pattern_setting") +table.insert(tests, "tests/netsync_client_absorbs_server_key") +table.insert(tests, "tests/netsync_verifies_server_keys") +table.insert(tests, "tests/test_a_merge_5") +table.insert(tests, "tests/empty_id_completion") +table.insert(tests, "tests/empty_string_as_a_path_name") +table.insert(tests, "tests/empty_environment") +table.insert(tests, "tests/short_options_work_correctly") +table.insert(tests, "tests/netsync_is_not_interrupted_by_SIGPIPE") +table.insert(tests, "tests/setup_creates__MTN_log") +table.insert(tests, "tests/checkout_creates__MTN_log") +table.insert(tests, "tests/commit_using__MTN_log") +table.insert(tests, "tests/commit_w_o__MTN_log_being_present") +table.insert(tests, "tests/commit_validation_lua_hook") +table.insert(tests, "tests/drop_a_public_key") +table.insert(tests, "tests/drop_a_public_and_private_key") +table.insert(tests, "tests/rename_moves_attributes") +table.insert(tests, "tests/automate_ancestors")