diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2013-08-25 14:45:19 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2013-08-25 14:45:19 +0100 |
commit | 59d1d18716527350ccefbfb8683b281639a98ca5 (patch) | |
tree | 45f6769d477f4478c345a24be4edc5bda8dee3e9 | |
parent | 3cc579e60abe5a952ca2ebdc788b1d907c2cdede (diff) | |
parent | 57d45c8ccda13d061db17df16f50821c775cf277 (diff) | |
download | gitano-59d1d18716527350ccefbfb8683b281639a98ca5.tar.gz |
Merge branch 'dsilvers/testing'
We know it's incomplete, but meh.
25 files changed, 662 insertions, 0 deletions
@@ -25,6 +25,17 @@ LIB_BINS := gitano-auth gitano-post-receive-hook gitano-update-hook \ BINS := gitano-setup +TEST_BIN_NAMES := gitano-test-tool + +TESTS := 01-basics 02-commands-as 02-commands-config 02-commands-copy \ + 02-commands-count-objects 02-commands-create 02-commands-destroy \ + 02-commands-fsck 02-commands-gc 02-commands-graveyard \ + 02-commands-group 02-commands-help 02-commands-ls 02-commands-readme \ + 02-commands-rename 02-commands-set-description 02-commands-set-head \ + 02-commands-set-owner 02-commands-sshkey 02-commands-user \ + 02-commands-whoami + + MODS := gitano \ \ gitano.util \ @@ -54,6 +65,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 +106,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 +138,10 @@ install-skel: for SKELFILE in $(SKEL_FILES); do \ install -m 644 skel/$$SKELFILE $(SKEL_INST_PATH)/$$SKELFILE; \ done + +test: local $(TEST_BINS) + @$(YARN) --env GTT="$$(pwd)/testing/gitano-test-tool" \ + 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..18f2e4f --- /dev/null +++ b/testing/01-basics.yarn @@ -0,0 +1,106 @@ +<!-- -*- 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 + +Users can see what groups they are in +------------------------------------- + +In this scenario we take a standard instance and ensure that the `testinstance` +user can access their user information (their `whoami` output) and that +information lists the `gitano-admin` group which they should be a member of. + + SCENARIO whoami shows the gitano-admin group + + GIVEN a standard instance + WHEN testinstance adminkey runs whoami + THEN stdout contains gitano-admin + +Then, just to be sure, we create a new user and ensure that it does not have +membership of `gitano-admin` + + GIVEN a unix user called alice + AND alice has keys called main + WHEN testinstance, using adminkey, adds user alice, using alice main + AND alice main runs whoami + THEN stdout does not contain gitano-admin + +Non-admin users cannot see the `gitano-admin` repository +-------------------------------------------------------- + +In this scenario we take a standard instance, add a user to it, and verify that +when the new user runs 'ls' it doesn't get to see `gitano-admin` but that the +`testinstance` user gets to see it and has `RW` privs. + + SCENARIO ls will not show repositories you have no access to + + GIVEN a standard instance + AND a unix user called alice + AND alice has keys called main + WHEN testinstance, using adminkey, adds user alice, using alice main + AND alice main runs ls + THEN stdout does not contain gitano-admin + WHEN testinstance adminkey runs ls + THEN stdout contains RW gitano-admin + +Basic repository creation +------------------------- + +In a default configuration, the only user who will be able to create +repositories. However creation can hand off ownership which means that we can +test that a new user who has a repository created for them can see it in ls. + + SCENARIO delegated repository creation works + + GIVEN a standard instance + AND a unix user called alice + AND alice has keys called main + WHEN testinstance, using adminkey, adds user alice, using alice main + AND testinstance adminkey runs create somerepo alice + AND alice main runs ls + THEN stdout contains RW somerepo + +And just to check, if the `testinstance` user created a non-delegated repo then +the `alice` user cannot see it. + + WHEN testinstance adminkey runs create anotherrepo + AND testinstance adminkey runs ls + THEN stdout contains RW anotherrepo + WHEN alice main runs ls + THEN stdout does not contain anotherrepo diff --git a/testing/02-commands-as.yarn b/testing/02-commands-as.yarn new file mode 100644 index 0000000..ce8afbf --- /dev/null +++ b/testing/02-commands-as.yarn @@ -0,0 +1,72 @@ +<!-- -*- markdown -*- --> +as --A- Become someone else +=========================== + +The `as` command can be used to run commands as different users. It should not +leak the existence/absence of a user, nor should it leak permissions from the +calling user into the effective user. + +Verification of `as` in the simple case +--------------------------------------- + +In the simple case, `as` is being called by someone who has permission to do +so, on behalf of a user which exists and can be used. + + SCENARIO Default case for as + + GIVEN a standard instance + AND testinstance has keys called other + WHEN testinstance, using adminkey, adds user other, using testinstance other + AND testinstance adminkey runs as other whoami + THEN stdout contains other + AND stdout does not contain gitano-admin + +The other trivial case is that a user without permission tries to run `as`. + + WHEN testinstance other, expecting failure, runs as other whoami + THEN stdout is empty + AND stderr contains Ruleset denied action + AND stderr contains exit:1 + +The final trivial case is that a user which can run `as` cannot use it to run +`as`. + + WHEN testinstance adminkey, expecting failure, runs as other as other whoami + THEN stdout is empty + AND stderr contains Cannot use 'as' to run 'as' + AND stderr contains Validation of command line failed + AND stderr contains exit:1 + +Security-related cases for `as` invocation +------------------------------------------ + +There are a number of security implications for the `as` command. In the +simplest of cases it is only necessary to grant gitano-admin members the right +to run commands `as` other users. In this way, only those who could otherwise +alter the users in the first place can act on their behalf. + +There is, however, a potential information leak -- namely if someone who does +not have the right to run commands 'as' another user runs an `as` with a user +which does not exist. It is critical that this simply be reported as a lack of +permission to run any command, and not leak that the target user does not exist +in any way. + + SCENARIO Ensuring 'as' does not leak user presence + + GIVEN a standard instance + AND testinstance has keys called other + WHEN testinstance, using adminkey, adds user other, using testinstance other + AND testinstance adminkey runs as other whoami + THEN stderr is empty + WHEN testinstance other, expecting failure, runs as badger whoami + THEN stdout is empty + AND stderr does not contain badger + +Finally we ensure that when a user who may run `as` commands does so, but +manages to typo a username, they get a useful error message. + + WHEN testinstance adminkey, expecting failure, runs as badger whoami + THEN stderr contains badger + AND stderr contains does not exist + AND stderr contains exit:1 + AND stdout is empty diff --git a/testing/02-commands-config.yarn b/testing/02-commands-config.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-config.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-copy.yarn b/testing/02-commands-copy.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-copy.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-count-objects.yarn b/testing/02-commands-count-objects.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-count-objects.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-create.yarn b/testing/02-commands-create.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-create.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-destroy.yarn b/testing/02-commands-destroy.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-destroy.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-fsck.yarn b/testing/02-commands-fsck.yarn new file mode 100644 index 0000000..115bbc6 --- /dev/null +++ b/testing/02-commands-fsck.yarn @@ -0,0 +1,65 @@ +<!-- -*- markdown -*- --> +fsck ---- Perform a fsck operation on a repository (Takes a repo) +================================================================= + +The `fsck` command is a basic pass-through to the underlying `git fsck` being +run on the remote repository. Apart from ensuring that the caller has `write` +access, to a repository which exists, no other checks are done and any spare +arguments are passed through to `git fsck`. + +Simple `fsck` usage +------------------- + +In the simple case a `gitano-admin` runs `fsck` against a repository which +definitely exists and as they are `gitano-admin` they have write access. + + SCENARIO Simple `fsck` cases + + GIVEN a standard instance + WHEN testinstance adminkey runs fsck gitano-admin + THEN stdout is empty + AND stderr is empty + +No matter how powerful you are, you cannot `fsck` a repository which does not +exist... + + WHEN testinstance adminkey, expecting failure, runs fsck somethingelse + THEN stdout is empty + AND stderr contains repository does not exist + +Attempting to `fsck` when you have no write access +-------------------------------------------------- + +Since any non-`gitano-admin` member cannot see `gitano-admin` we can use that +as a test case for ensuring that you must have write access in order to `fsck` +something. + + SCENARIO lowly accolyte fails to fsck + + GIVEN a standard instance + AND testinstance has keys called other + WHEN testinstance, using adminkey, adds user other, using testinstance other + AND testinstance other, expecting failure, runs fsck gitano-admin + THEN stdout is empty + AND stderr contains Ruleset denied action + +Passing commands through to `fsck` +---------------------------------- + +It is possible to pass arguments through to the `git fsck` subprocess. By +passing through a bad option, we get to see this in action + + SCENARIO passing arguments to `fsck` + + GIVEN a standard instance + WHEN testinstance adminkey, expecting failure, runs fsck gitano-admin --bad-option + THEN stdout is empty + +We check for `git fsck`'s usage message: + + AND stderr contains error: unknown option + AND stderr contains usage: git fsck + +And also we see that Gitano has caught the error + + AND stderr contains Unable to continue diff --git a/testing/02-commands-gc.yarn b/testing/02-commands-gc.yarn new file mode 100644 index 0000000..d1cff46 --- /dev/null +++ b/testing/02-commands-gc.yarn @@ -0,0 +1,69 @@ +<!-- -*- markdown -*- --> +gc ---- Invoke git gc on your repository (Takes a repo) +======================================================= + +The `gc` command is a basic pass-through to the underlying `git gc` being run +on the remote repository. Apart from ensuring that the caller has `write` +access, to a repository which exists, no other checks are done and any spare +arguments are passed through to `git gc`. + +Using `gc` in the simple case +----------------------------- + +So the simple case is that a `gitano-admin` runs `gc` on a repository which +definitely exists which means they always have the rights to do so. + + SCENARIO Simple case `gc` usage + + GIVEN a standard instance + WHEN testinstance adminkey runs gc gitano-admin + THEN stderr is empty + AND stdout is empty + +We can then ensure that if the repository does not exist, we get a useful error +message back: + + SCENARIO Simple failure case `gc` usage + + GIVEN a standard instance + WHEN testinstance adminkey, expecting failure, runs gc something + THEN stdout is empty + AND stderr contains repository does not exist + +Write access checks +------------------- + +A more complex case involves creating a repository to which a user has no write +permissions and trying to get that user to run `gc` on it. + + SCENARIO Write access checks for `gc` usage + + GIVEN a standard instance + AND testinstance has keys called other + WHEN testinstance, using adminkey, adds user other, using testinstance other + AND testinstance adminkey runs create testrepo + AND testinstance other, expecting failure, runs gc testrepo + THEN stdout is empty + AND stderr contains Ruleset denied action + +Passing arguments to `git gc` +----------------------------- + +Any spare arguments given to `gc` are passed through to `git gc` untouched. We +can verify that arguments are passed through by passing a bad argument through +and seeing if we get an error message from the underlying `git gc` instance: + + SCENARIO Passing arguments through to `git gc` + + GIVEN a standard instance + WHEN testinstance adminkey, expecting failure, runs gc gitano-admin --not-valid + THEN stdout is empty + +These are the `git gc` errors + + AND stderr contains error: unknown option + AND stderr contains usage: git gc + +And this demonstrates that Gitano detected the error properly + + AND stderr contains Unable to continue diff --git a/testing/02-commands-graveyard.yarn b/testing/02-commands-graveyard.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-graveyard.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-group.yarn b/testing/02-commands-group.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-group.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-help.yarn b/testing/02-commands-help.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-help.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-ls.yarn b/testing/02-commands-ls.yarn new file mode 100644 index 0000000..8ead9da --- /dev/null +++ b/testing/02-commands-ls.yarn @@ -0,0 +1,21 @@ +<!-- -*- markdown -*- --> + +`ls [--verbose|-v] [<pattern>...]` +================================== + +The `ls` command is one of the few which touch every repository in a Gitano +instance. As such, it can take a while to run. Theoretically it leaks the +number of Git repositories on the server by virtue of analysis of timing. + +Basic operation +=============== + +Firstly, we verify the basic operation of ls, that as a gitano-admin we have +read access (at least) to everything and as such we can list all the +repositories. + + SCENARIO Basic operation of ls + GIVEN a standard instance + WHEN testinstance adminkey runs ls + THEN stdout contains RW gitano-admin + AND stderr is empty diff --git a/testing/02-commands-readme.yarn b/testing/02-commands-readme.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-readme.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-rename.yarn b/testing/02-commands-rename.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-rename.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-set-description.yarn b/testing/02-commands-set-description.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-set-description.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-set-head.yarn b/testing/02-commands-set-head.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-set-head.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-set-owner.yarn b/testing/02-commands-set-owner.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-set-owner.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-sshkey.yarn b/testing/02-commands-sshkey.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-sshkey.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-user.yarn b/testing/02-commands-user.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-user.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/02-commands-whoami.yarn b/testing/02-commands-whoami.yarn new file mode 100644 index 0000000..f282cb0 --- /dev/null +++ b/testing/02-commands-whoami.yarn @@ -0,0 +1 @@ +<!-- -*- markdown -*- --> diff --git a/testing/gitano-test-tool.in b/testing/gitano-test-tool.in new file mode 100644 index 0000000..c931b6d --- /dev/null +++ b/testing/gitano-test-tool.in @@ -0,0 +1,181 @@ +-- @@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 not (how == "exit" and why == 0) then + io.stderr:write(how .. ":" .. tostring(why).."\n") + os.exit(1) + 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..c49021e --- /dev/null +++ b/testing/library.yarn @@ -0,0 +1,104 @@ +<!-- -*- 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 WHEN ([a-z][a-z0-9]*) ([a-z][a-z0-9]*) runs (.+) + $GTT runcommand $MATCH_1 $MATCH_2 $MATCH_3 > $DATADIR/stdout 2> $DATADIR/stderr + + IMPLEMENTS WHEN ([a-z][a-z0-9]*) ([a-z][a-z0-9]*),? expecting failure,? runs (.+) + if $GTT runcommand $MATCH_1 $MATCH_2 $MATCH_3 > $DATADIR/stdout 2> $DATADIR/stderr; then + false + fi + + IMPLEMENTS THEN ([^ ]+) contains (.+) + grep -q "$MATCH_2" $DATADIR/"$MATCH_1" + + IMPLEMENTS THEN ([^ ]+) does not contain (.+) + if grep -q "$MATCH_2" $DATADIR/"$MATCH_1"; then false; else true; fi + + IMPLEMENTS THEN ([^ ]+) is empty + if grep -q . $DATADIR/"$MATCH_1"; then false; fi + + IMPLEMENTS THEN failure ensues + cd $DATADIR + echo "FIND:" + find . + echo "KEYS:" + cat user-home-testinstance/.ssh/authorized_keys + echo "OUT": + cat stdout + echo "ERR": + cat stderr + /bin/false + |