diff --git a/Makefile b/Makefile
index 45737b5456417caadf64c5b9a6daadafa9ca52b8..45fb85ae986b2dbbbea7ba99198a4074d1ec6017 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,8 @@
 IMAGE:=dbscripts/test
 RUN_OPTIONS:=--rm --network=none -v $(PWD):/dbscripts:ro --tmpfs=/tmp:exec -w /dbscripts/test
 CASES ?= cases
-BATS_ARGS ?=
+JOBS ?= $(shell nproc)
+BATS_ARGS ?= --jobs $(JOBS) --verbose-run
 DOCKER ?= docker
 
 test-image:
diff --git a/test/Dockerfile b/test/Dockerfile
index f54c87d517682651339033bfa031fab4a0de3a4a..ec54236a5c9f4ab6831c405e733b4f8edcc3b602 100644
--- a/test/Dockerfile
+++ b/test/Dockerfile
@@ -54,6 +54,10 @@ RUN pacman-key --init && \
 		/srv/ftp/{{core,extra,multilib}{,-testing,-staging},gnome-unstable}/os/x86_64/ && \
 	echo -e "[safe]\n\tdirectory = *\n" > /etc/gitconfig
 
+# TODO: temporary hack to work around bats packaging bug
+RUN sed 's/libexec/lib/g' -i /usr/lib/bats/* && \
+	sed 's/bats-core/bats/g' -i /usr/lib/bats/*
+
 USER tester
 
 RUN echo -e "\
diff --git a/test/Makefile b/test/Makefile
index 556afa51843baf501f830816448d51bd0ba42889..0a53c6aeafdcefb9d17b3b4751e697d16d4719e0 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,5 +1,6 @@
 CASES ?= cases
-BATS_ARGS ?=
+JOBS ?= $(shell nproc)
+BATS_ARGS ?= --jobs $(JOBS) --verbose-run
 
 test:
 	BUILDDIR=/build PATH=$(CURDIR)/../:$(CURDIR)/../cron-jobs/:$(PATH) bats $(BATS_ARGS) $(CASES)
diff --git a/test/cases/setup_suite.bash b/test/cases/setup_suite.bash
new file mode 100644
index 0000000000000000000000000000000000000000..ea7f4000c818e391a8544d2fc1d4c726ea51a646
--- /dev/null
+++ b/test/cases/setup_suite.bash
@@ -0,0 +1,6 @@
+setup_suite() {
+	git config --global user.email "tester@localhost"
+	git config --global user.name "Bob Tester"
+	git config --global init.defaultBranch main
+	git config --global advice.detachedHead false
+}
diff --git a/test/lib/common.bash b/test/lib/common.bash
index 57e0bd313bd9b37244bcbbaaecf98ca900b59cd7..aa5552e7b66b25fbc2cadd073e36e11d6cc214db 100644
--- a/test/lib/common.bash
+++ b/test/lib/common.bash
@@ -70,6 +70,32 @@ __isGlobfile() {
 	[[ -f $1 ]]
 }
 
+##
+#  usage : lock( $fd, $file )
+##
+lock() {
+	# Only reopen the FD if it wasn't handed to us
+	if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
+		mkdir -p -- "$(dirname -- "$2")"
+		eval "exec $1>"'"$2"'
+	fi
+
+	if ! flock --wait 600 "$1"; then
+		error "Failed to acquire lock on %s" "$2"
+		exit 1
+	fi
+}
+
+##
+#  usage : lock_close( $fd )
+##
+lock_close() {
+	local fd=$1
+	# https://github.com/koalaman/shellcheck/issues/862
+	# shellcheck disable=2034
+	exec {fd}>&-
+}
+
 __buildPackage() {
 	local pkgdest=${1:-.}
 	local p
@@ -80,10 +106,12 @@ __buildPackage() {
 
 	if [[ -n ${BUILDDIR} ]]; then
 		cache=${BUILDDIR}/$(__getCheckSum PKGBUILD)
+		mkdir -p "${cache}"
+		lock 9 "${cache}/.lock"
+
 		if cp -Lv ${cache}/*${PKGEXT}{,.sig} ${pkgdest} 2>/dev/null; then
+			lock_close 9
 			return 0
-		else
-			mkdir -p ${cache}
 		fi
 	fi
 
@@ -110,6 +138,7 @@ __buildPackage() {
 			cp -Lv ${p}{,.sig} ${cache}/
 		fi
 	done
+	lock_close 9
 }
 
 __archrelease() {
@@ -195,12 +224,6 @@ eot
 
 	. config
 
-	git config --global user.email "tester@localhost"
-	git config --global user.name "Bob Tester"
-	git config --global init.defaultBranch main
-	git config --global advice.detachedHead false
-
-
 	# This is for our git clones when initializing bare repos
 	TMP_WORKDIR_GIT=${TMP}/git-clones