summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2013-06-22 11:45:47 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2013-06-22 11:57:59 +0100
commit9842c826f1fb667feb006693ab10cb18c774f8e5 (patch)
tree27a8dada8f1b95754a204675dc18e7101845cb19
parent10c24e03326ea7d69485af0271c8be77033abf08 (diff)
downloadgitano-9842c826f1fb667feb006693ab10cb18c774f8e5.tar.bz2
Initial testing tool, library and basic test
The tool (testing/gitano-test-tool.in) provides a bunch of complex behaviours which are then used by the scenario test implementations in testing/library.yarn. From there, those implementations for scenario tests which are in the rest of the .yarn files in testing/. A top level 'make test' will invoke the test suite.
-rw-r--r--Makefile20
-rw-r--r--testing/.gitignore1
-rw-r--r--testing/01-basics.yarn41
-rw-r--r--testing/gitano-test-tool.in189
-rw-r--r--testing/library.yarn81
5 files changed, 332 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 8c49fc4..eef10ac 100644
--- a/Makefile
+++ b/Makefile
@@ -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
+