diff options
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | testing/.gitignore | 1 | ||||
-rw-r--r-- | testing/01-basics.yarn | 41 | ||||
-rw-r--r-- | testing/gitano-test-tool.in | 189 | ||||
-rw-r--r-- | testing/library.yarn | 81 |
5 files changed, 332 insertions, 0 deletions
@@ -25,6 +25,10 @@ LIB_BINS := gitano-auth gitano-post-receive-hook gitano-update-hook \ BINS := gitano-setup +TEST_BIN_NAMES := gitano-test-tool + +TESTS := 01-basics + MODS := gitano \ \ gitano.util \ @@ -54,6 +58,13 @@ SRC_MOD_FILES := $(patsubst %,lib/%,$(MOD_FILES)) LOCAL_BINS := $(patsubst %,bin/%,$(BINS) $(LIB_BINS)) LIB_BIN_SRCS := $(patsubst %,bin/%.in,$(LIB_BINS)) +TEST_BINS := $(patsubst %,testing/%,$(TEST_BIN_NAMES)) +TEST_BIN_SRCS := $(patsubst %,%.in,$(TEST_BINS)) + +YARN := yarn + +TESTS := $(patsubst %,testing/%.yarn,$(TESTS)) + GEN_BIN := utils/install-lua-bin RUN_GEN_BIN := $(LUA) $(GEN_BIN) $(LUA) define GEN_LOCAL_BIN @@ -88,6 +99,8 @@ local: $(LOCAL_BINS) clean: @echo "CLEAN: local binaries" @$(RM) $(LOCAL_BINS) + @echo "CLEAN: test binaries" + @$(RM) $(TEST_BINS) distclean: clean @find . -name "*~" -delete @@ -118,3 +131,10 @@ install-skel: for SKELFILE in $(SKEL_FILES); do \ install -m 644 skel/$$SKELFILE $(SKEL_INST_PATH)/$$SKELFILE; \ done + +test: local $(TEST_BINS) + @env GTT="$$(pwd)/testing/gitano-test-tool" \ + $(YARN) testing/library.yarn $(TESTS) + +testing/%: testing/%.in $(GEN_BIN) + $(call GEN_LOCAL_BIN,$<,$@) diff --git a/testing/.gitignore b/testing/.gitignore new file mode 100644 index 0000000..bf632a4 --- /dev/null +++ b/testing/.gitignore @@ -0,0 +1 @@ +gitano-test-tool diff --git a/testing/01-basics.yarn b/testing/01-basics.yarn new file mode 100644 index 0000000..0e083ce --- /dev/null +++ b/testing/01-basics.yarn @@ -0,0 +1,41 @@ +<!-- -*- markdown -*- --> +Basic tests for Gitano +====================== + +In these basic tests for Gitano we start life by creating a standard +installation and verifying some of the very basics of Gitano's core +functionality. + +Basic behaviour +--------------- + +In this scenario we verify that we can create a standard instance and then +clone the `gitano-admin` repository. Once we've done that we also verify that +we can create a user, give it an ssh key, that the user's creation is reflected +in the `gitano-admin` repository and that we can remove the user and the +removal is also reflected. + + SCENARIO Verification of basic behaviour + +Step 1 is to create a standard instance and clone `gitano-admin` + + GIVEN a standard instance + WHEN testinstance, using adminkey, clones gitano-admin as gitano-admin + THEN testinstance has a clone of gitano-admin + +Next we create the user (alice) and verify that `gitano-admin` shows her. + + GIVEN a unix user called alice + AND alice has keys called main + WHEN testinstance, using adminkey, adds user alice, using alice main + AND git pull happens in testinstance gitano-admin + THEN testinstance gitano-admin has a file called users/alice/user.conf + AND testinstance gitano-admin has a file called users/alice/default.key + +Finally we remove that user and verify that `gitano-admin` reflects that too. + + WHEN testinstance, using adminkey, deletes user alice + AND git pull happens in testinstance gitano-admin + THEN testinstance gitano-admin has no file called users/alice/user.conf + AND testinstance gitano-admin has no file called users/alice/default.key + diff --git a/testing/gitano-test-tool.in b/testing/gitano-test-tool.in new file mode 100644 index 0000000..ff386fd --- /dev/null +++ b/testing/gitano-test-tool.in @@ -0,0 +1,189 @@ +-- @@SHEBANG +-- -*- lua -*- +-- gitano-test-tool +-- +-- Git (with) Augmented network operations -- testing tool +-- +-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org> +-- +-- + +-- @@GITANO_LUA_PATH + +local gitano = require "gitano" +local gall = require "gall" +local luxio = require "luxio" +local sio = require "luxio.simple" +local sp = require "luxio.subprocess" + +-- @@GITANO_BIN_PATH +-- @@GITANO_SHARE_PATH + +local argv = {...} +local basedir = (luxio.getenv "DATADIR") .. "/" + +local function user_home(username) + return basedir .. "user-home-" .. username +end + +local function ssh_base(username) + return user_home(username) .. "/.ssh" +end + +local function ssh_key_file(username, keyname) + return ssh_base(username) .. "/" .. keyname +end + +local function unix_assert(ret, errno) + if ret ~= 0 then + error(luxio.strerror(errno)) + end +end + +local function run_program(t) + local proc = sp.spawn_simple(t) + local how, why = proc:wait() + if how == -1 then + unix_assert(how, why) + end + if how ~= "exit" then + for i = 1, #t do + print(t[i]) + end + error("BLEH: " .. how .. ":" .. tostring(why)) + end + if why ~= 0 then + for i = 1, #t do + print(t[i]) + end + error("BLEH: " .. how .. ":" .. tostring(why)) + end +end + +local function esc_quote_all(t) + local tt = {} + for i = 1, #t do + tt[i] = ("%q"):format(t[i]) + end + return table.concat(tt, " ") +end + +local function load_auth(fname) + local fh = io.open(fname, "r") + local line = fh:read("*l") + local ret = {} + while line do + line = line:gsub("^ *", "") + line = line:gsub(" *$", "") + line = line:gsub("^#.*", "") + if line ~= "" then + local repopath, user, keyset, key = + line:match('^[^\\]+\\"([^"]+)\\" \\"([^"]+)\\" \\"([^"]+)\\""[^ ]+ (.+)$') + assert(repopath, line) + ret[#ret+1] = { + repopath = repopath, + user = user, + keyset = keyset, + key = key + } + ret[key] = ret[#ret] + end + line = fh:read("*l") + end + fh:close() + return ret +end + +local function generate_exturl(user, key, repo) + local authkeys = load_auth(ssh_key_file("testinstance", "authorized_keys")) + local pubkey = (sio.open(ssh_key_file(user, key) .. ".pub", "r")):read("*l") + local authline = assert(authkeys[pubkey]) + local extfmt = "ext::env HOME=%s SSH_ORIGINAL_COMMAND=%s %s %s %s %s" + local function esc(s) + return ((s:gsub("%%", "%%%%")):gsub(" ", "%% ")) + end + return (extfmt):format(esc(user_home("testinstance")), + "%S% " .. esc(repo), + esc(gitano.config.lib_bin_path() .. "/gitano-auth"), + esc(authline.repopath), + esc(authline.user), esc(authline.keyset)) +end + +function cmd_createunixuser(username) + assert(sio.mkdir(user_home(username), "0755")) + assert(sio.mkdir(ssh_base(username), "0755")) +end + +function cmd_createsshkey(username, keyname, optionaltype) + optionaltype = optionaltype or "rsa" + run_program { + "ssh-keygen", "-q", + "-t", optionaltype, + "-C", username .. "-" .. optionaltype .. "@" .. keyname, + "-f", ssh_key_file(username, keyname), + "-N", "" } +end + +function cmd_setupstandard(owning_user, master_key) + local clodname = basedir .. "setup.clod" + local fh = io.open(clodname, "w") + fh:write('setup.batch "true"\n') + fh:write(('paths.pubkey %q\n'):format(ssh_key_file(owning_user, master_key) .. ".pub")) + fh:write('site.name "Gitano Test Instance"\n') + fh:write('log.prefix "gitano-test"\n') + fh:write(('admin.keyname %q\n'):format(master_key)) + fh:close() + run_program { + "gitano-setup", clodname, + exe = gitano.config.lib_bin_path() .. "/gitano-setup", + env = { HOME = user_home(owning_user) } + } +end + +function cmd_cloneviassh(user, key, repo, localname) + local exturl = generate_exturl(user, key, repo) + run_program { + "git", "clone", exturl, user_home(user) .. "/" .. localname, + } +end + +function cmd_cloneexists(user, localname) + run_program { + "git", "fsck", user_home(user) .. "/" .. localname + } +end + +function cmd_pubkeyfilename(user, key) + print(ssh_key_file(user, key) .. ".pub") +end + +function cmd_runcommand(user, key, ...) + local authkeys = load_auth(ssh_key_file("testinstance", "authorized_keys")) + local pubkey = (sio.open(ssh_key_file(user, key) .. ".pub", "r")):read("*l") + local authline = assert(authkeys[pubkey]) + local cmdline = { + gitano.config.lib_bin_path() .. "/gitano-auth", + authline.repopath, authline.user, authline.keyset, + env = {HOME = user_home("testinstance")} + } + cmdline.env.SSH_ORIGINAL_COMMAND = esc_quote_all({...}) + run_program(cmdline) +end + +function cmd_clonelocation(user, localname) + print(user_home(user) .. "/" .. localname) +end + +function cmd_findtoken() + local input = sio.stdin:read("*a") + local token = input:match("("..("[0-9a-f]"):rep(40)..")") + assert(token, "Cannot find a token") + print(token) +end + +local cmd = table.remove(argv, 1) +if _G['cmd_' .. cmd] then + _G['cmd_' .. cmd](unpack(argv)) +else + error("Unknown command: " .. cmd) +end diff --git a/testing/library.yarn b/testing/library.yarn new file mode 100644 index 0000000..105e4c8 --- /dev/null +++ b/testing/library.yarn @@ -0,0 +1,81 @@ +<!-- -*- markdown -*- --> +Test library for Gitano +======================= + +When running tests under yarn, for each scenario, we are provided with a +temporary working directory called `$DATADIR` which is a fresh directory for +each scenario being run. Within that base, we can set up any number of fake +SSH keys, a fake Gitano instance, fake users, and use them to make clones, do +pushes etc. Nearly all of the implementations rely on a tool in the testing +directory called `gitano-test-tool` the path to which is available as `$GTT`. + +For ease of testing, the fake user who gets to "own" the Gitano instance will +be called `testinstance` and the keyset which they get to use in order to +access the repository will be called `adminkey`. This is important when it +comes to cloning, pushing, etc. + +Managing the fake unix users +---------------------------- + + IMPLEMENTS GIVEN a unix user called ([a-z][a-z0-9]*) + $GTT createunixuser $MATCH_1 + + IMPLEMENTS GIVEN ([a-z][a-z0-9]*) has keys called ([a-z][a-z0-9]*) + $GTT createsshkey $MATCH_1 $MATCH_2 + +General instance management +--------------------------- + + IMPLEMENTS GIVEN a standard instance + $GTT createunixuser testinstance + $GTT createsshkey testinstance adminkey + $GTT setupstandard testinstance adminkey + +Repository access +----------------- + + IMPLEMENTS WHEN ([a-z][a-z0-9]*),? using ([a-z][a-z0-9]*),? clones ([^ ]+) as ([^ ]+) + $GTT cloneviassh $MATCH_1 $MATCH_2 "$MATCH_3" "$MATCH_4" + +Clone manipulation +------------------ + + IMPLEMENTS THEN ([a-z][a-z0-9]*) has a clone of ([^ ]+) + $GTT cloneexists $MATCH_1 "$MATCH_2" + + IMPLEMENTS WHEN git pull happens in ([a-z][a-z0-9]*) ([^ ]+) + cd "$($GTT clonelocation $MATCH_1 "$MATCH_2")" + git pull + + IMPLEMENTS THEN ([a-z][a-z0-9]*) ([^ ]+) has a file called (.+) + cd "$($GTT clonelocation $MATCH_1 "$MATCH_2")" + test -r "$MATCH_3" + + IMPLEMENTS THEN ([a-z][a-z0-9]*) ([^ ]+) has no file called (.+) + set -x + cd "$($GTT clonelocation $MATCH_1 "$MATCH_2")" + if test -r "$MATCH_3"; then false; else true; fi + +Admin repo manipulation +----------------------- + + IMPLEMENTS WHEN ([a-z][a-z0-9]*),? using ([a-z][a-z0-9]*),? adds user ([a-z][a-z0-9]*),? using ([a-z][a-z0-9]*) ([a-z][a-z0-9]*) + $GTT runcommand $MATCH_1 $MATCH_2 \ + user add $MATCH_3 $MATCH_3@testinstance "$MATCH_3's real name" + $GTT runcommand $MATCH_1 $MATCH_2 \ + as $MATCH_3 sshkey add default < \ + $($GTT pubkeyfilename $MATCH_4 $MATCH_5) + + IMPLEMENTS WHEN ([a-z][a-z0-9]*),? using ([a-z][a-z0-9]*),? deletes user ([a-z][a-z0-9]*) + TOKEN=$($GTT runcommand $MATCH_1 $MATCH_2 user del $MATCH_3 2>&1 | $GTT findtoken) + $GTT runcommand $MATCH_1 $MATCH_2 user del $MATCH_3 $TOKEN + +Generic utility methods +----------------------- + + IMPLEMENTS THEN failure ensues + cd $DATADIR + find . + cat user-home-testinstance/.ssh/authorized_keys + /bin/false + |