Skip to content

Commit

Permalink
test: add some tests and launch them in docker instead of runner host
Browse files Browse the repository at this point in the history
  • Loading branch information
williarin committed Jan 6, 2022
1 parent d800de1 commit ca72be2
Show file tree
Hide file tree
Showing 19 changed files with 362 additions and 61 deletions.
20 changes: 16 additions & 4 deletions .github/workflows/test-build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ jobs:
with:
submodules: recursive

- name: Install testing tools
run: sudo apt install -y shellcheck faketime
- name: Launch Docker containers
run: docker compose -f docker-compose.test.yml up -d --build

- name: Test
run: make test
run: docker compose -f docker-compose.test.yml exec backup make test

build:
name: Build
Expand Down Expand Up @@ -82,6 +82,14 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')

steps:
- uses: FranzDiebold/github-env-vars-action@v2

- name: Set major tag name
run: echo "TAG_MAJOR=$(echo $CI_REF_NAME | cut -d. -f1)" >> $GITHUB_ENV

- name: Set major tag name
run: echo "TAG_MINOR=${{ env.TAG_MAJOR }}.$(echo $CI_REF_NAME | cut -d. -f2)" >> $GITHUB_ENV

- name: Download artifact
uses: actions/download-artifact@v2
with:
Expand All @@ -96,4 +104,8 @@ jobs:
- name: Push Docker image
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push --all-tags williarin/secure-mysql-backups
docker push \
williarin/secure-mysql-backups:latest \
williarin/secure-mysql-backups:$CI_REF_NAME \
williarin/secure-mysql-backups:${{ env.TAG_MAJOR }} \
williarin/secure-mysql-backups:${{ env.TAG_MINOR }}
2 changes: 1 addition & 1 deletion .shellcheckrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
disable=SC1090
disable=SC1090,SC2012
17 changes: 14 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@ RUN apk --update add \
COPY ./src/ /usr/local/bin
COPY ./logrotate.d/* /etc/logrotate.d/

CMD [ "run" ]
CMD [ "run-cron" ]


FROM base AS dev
FROM base AS test

COPY --from=trajano/alpine-libfaketime /faketime.so /lib/faketime.so
COPY --from=trajano/alpine-libfaketime /faketime.so /lib/faketime.so
ENV LD_PRELOAD=/lib/faketime.so

RUN apk add shellcheck make \
&& mkdir -p /usr/src/secure-mysql-backups

COPY ./src/ /usr/src/secure-mysql-backups/src/
COPY ./test/ /usr/src/secure-mysql-backups/test/
COPY ./Makefile /usr/src/secure-mysql-backups

WORKDIR /usr/src/secure-mysql-backups

CMD [ "tail", "-f", "/dev/null" ]
10 changes: 3 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
all: test build
all: test

.PHONY: test
test:
@for file in $$(find src -type f); do shellcheck --format=tty $$file; done;
@sudo ./test/bats/bin/bats test/unit

.PHONY: build
build:
docker build -t williarin/secure-mysql-backups:latest --target base .
@for file in $$(find ./src -type f); do shellcheck -e 1091,2012 --format=tty $$file; done;
@./test/bats/bin/bats test/unit
19 changes: 19 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Docker Compose file for executing test suite

version: '3.8'

services:
database:
image: mysql:8
restart: 'no'
environment:
- MYSQL_DATABASE=my_db
- MYSQL_ROOT_PASSWORD=root

backup:
build:
context: .
target: test
restart: 'no'
depends_on:
- database
24 changes: 0 additions & 24 deletions docker-compose.yml

This file was deleted.

2 changes: 1 addition & 1 deletion src/backup
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ backup_name="$(get_env "BACKUP_NAME" "main-backup")"
echo "Backup started at $(date)."

for database in $databases; do
dump "$host" "$port" "$user" "$password" "$database" || continue
dump_database "$host" "$port" "$user" "$password" "$database" || continue

if [ "$individual_backups" = true ]; then
archive_file="$(get_archive_name "$backup_name.$database")"
Expand Down
62 changes: 54 additions & 8 deletions src/lib/db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

#/ Retrieve the list of all databases, excluding system databases
#/
#/ @usage var="$(mysql_command "localhost" "3306" "root" "root" "SHOW DATABASES;")"
#/
#/ @param $1 Host
#/ @param $2 Port
#/ @param $3 User
#/ @param $4 Password
#/ @param $5 Command
#/ @return Prints the command result
mysql_command () {
if [ "$#" -ne 5 ]; then
echo "5 arguments required, $# provided"
exit 1
fi

mysql -h "$1" -P "$2" -u "$3" -p"$4" -srN -e "$5"
}

#/ Retrieve a space-separated list of all databases, excluding system databases
#/
#/ @usage var="$(get_databases_list "localhost" "3306" "root" "root")"
#/
#/ @param $1 Host
Expand All @@ -11,32 +30,59 @@
#/ @return Prints the result
get_databases_list () {
if [ "$#" -ne 4 ]; then
echo "4 argument required, $# provided"
echo "4 arguments required, $# provided"
exit 1
fi

mysql -h "$1" -P "$2" -u "$3" -p"$4" -e "SHOW DATABASES;" \
| tr -d "| " \
| grep -Ev "Database|sys|mysql|(information|performance)_schema" \
mysql_command "$1" "$2" "$3" "$4" "SHOW DATABASES;" \
| grep -Ev "sys|mysql|(information|performance)_schema" \
| tr '\n' ' ' \
| sed 's/[ \r\n]*$//'
}

#/ Dump a single database in /tmp/backup/
#/
#/ @usage dump "localhost" "3306" "root" "root" "database_name"
#/ @usage dump_database "localhost" "3306" "root" "root" "database_name"
#/
#/ @param $1 Host
#/ @param $2 Port
#/ @param $3 User
#/ @param $4 Password
#/ @param $4 Database name
dump () {
#/ @param $5 Database name
dump_database () {
if [ "$#" -ne 5 ]; then
echo "5 argument required, $# provided"
echo "5 arguments required, $# provided"
exit 1
fi

mkdir -p "/tmp/backup"
mysqldump --single-transaction -h "$1" -P "$2" -u "$3" -p"$4" "$5" 2>/dev/null > "/tmp/backup/$5.sql"
}

#/ Wait for database to be reachable
#/
#/ @usage wait_for_database "localhost" "3306" "root" "root" "60"
#/
#/ @param $1 Host
#/ @param $2 Port
#/ @param $3 User
#/ @param $4 Password
#/ @param $5 Max attempts
wait_for_database () {
if [ "$#" -ne 5 ]; then
echo "5 arguments required, $# provided"
exit 1
fi

attempts=$5

until [ "$attempts" -eq 0 ] || database_error=$(mysql -h "$1" -P "$2" -u "$3" -p"$4" --connect-timeout=1 -e "SELECT 1" 2>&1); do
sleep 1
attempts=$((attempts - 1))
done

if [ $attempts -eq 0 ]; then
echo "The database is not reachable: $database_error"
exit 1
fi
}
42 changes: 42 additions & 0 deletions src/lib/file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,48 @@
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
source "$SCRIPT_DIR/env.sh"

#/ Get the file UID, even if the user doesn't exist
#/
#/ @usage var="$(get_file_uid "path/to/file")"
#/
#/ @param $1 Path to file
#/ @return Prints the UID of the file
get_file_uid () {
if [ "$#" -ne 1 ]; then
echo "1 argument required, $# provided"
exit 1
fi

if [ ! -f "$1" ]; then
echo "File $1 does not exist"
exit 1
fi

id -u "$(ls -ld "$1" | awk '{print $3}')" 2>/dev/null \
|| ls -ld "$1" | awk '{print $3}'
}

#/ Get the file GID, even if the group doesn't exist
#/
#/ @usage var="$(get_file_gid "path/to/file")"
#/
#/ @param $1 Path to file
#/ @return Prints the GID of the file
get_file_gid () {
if [ "$#" -ne 1 ]; then
echo "1 argument required, $# provided"
exit 1
fi

if [ ! -f "$1" ]; then
echo "File $1 does not exist"
exit 1
fi

id -g "$(ls -ld "$1" | awk '{print $4}')" 2>/dev/null \
|| ls -ld "$1" | awk '{print $4}'
}

#/ Get an archive name corresponding to the current name
#/
#/ @usage var="$(get_archive_name "my-backup-name")"
Expand Down
File renamed without changes.
13 changes: 7 additions & 6 deletions test/unit/create_archive.bats
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ setup() {
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR/../../src:$DIR/../../src/lib:$PATH"

sudo mkdir -p /tmp/backup /backup
sudo chown "$USER:$GROUP" /tmp/backup /backup
mkdir -p /tmp/backup /backup
chown "$USER:$GROUP" /tmp/backup /backup
}

@test "fails if no argument given" {
Expand Down Expand Up @@ -87,20 +87,21 @@ setup() {

echo "MYSQL_DUMP" > /tmp/backup/my_db.sql

CHOWN_FILES="1000:1000"
CHOWN_FILES="1000:2500"

run create_archive "my-backup-name.my_db.day1-Monday.tgz" "my_db.sql"
[ "$status" -eq 0 ]
[ -f "/backup/my-backup-name.my_db.day1-Monday.tgz" ]
[ ! -f "/tmp/backup/my_db.sql" ]
[ "$(id -u $(stat -c "%U" "/backup/my-backup-name.my_db.day1-Monday.tgz"))" -eq 1000 ]
[ "$(id -g $(stat -c "%G" "/backup/my-backup-name.my_db.day1-Monday.tgz"))" -eq 1000 ]
[ "$(get_file_uid "/backup/my-backup-name.my_db.day1-Monday.tgz")" -eq 1000 ]
[ "$(get_file_gid "/backup/my-backup-name.my_db.day1-Monday.tgz")" -eq 2500 ]

run tar xzf "/backup/my-backup-name.my_db.day1-Monday.tgz" -C /backup/
[ "$status" -eq 0 ]
[ -f "/backup/my_db.sql" ]
[ "$(cat /backup/my_db.sql)" == "MYSQL_DUMP" ]
[ "$(id -u $(stat -c "%U" "/backup/my_db.sql"))" -eq 1000 ]
[ "$(get_file_uid "/backup/my_db.sql")" -eq 1000 ]
[ "$(get_file_gid "/backup/my_db.sql")" -eq 2500 ]

run rm -f /backup/my_db.sql /backup/my-backup-name.my_db.day1-Monday.tgz
}
Expand Down
8 changes: 4 additions & 4 deletions test/unit/decrypt_archive.bats
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ setup() {
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR/../../src:$DIR/../../src/lib:$PATH"

sudo mkdir -p /tmp/backup /backup
sudo chown "$USER:$GROUP" /tmp/backup /backup
mkdir -p /tmp/backup /backup
chown "$USER:$GROUP" /tmp/backup /backup
}

@test "fails if no argument given" {
Expand Down Expand Up @@ -56,8 +56,8 @@ setup() {
run decrypt_archive "my-backup-name.my_db.day1-Monday.tgz.aes"
[ "$status" -eq 0 ]
[ -f "/backup/my-backup-name.my_db.day1-Monday.tgz" ]
[ "$(id -u $(stat -c "%U" "/backup/my-backup-name.my_db.day1-Monday.tgz"))" -eq 1000 ]
[ "$(id -g $(stat -c "%G" "/backup/my-backup-name.my_db.day1-Monday.tgz"))" -eq 1000 ]
[ "$(get_file_uid "/backup/my-backup-name.my_db.day1-Monday.tgz")" -eq 1000 ]
[ "$(get_file_gid "/backup/my-backup-name.my_db.day1-Monday.tgz")" -eq 1000 ]

run tar xzf "/backup/my-backup-name.my_db.day1-Monday.tgz" -C /backup/
[ "$status" -eq 0 ]
Expand Down
24 changes: 24 additions & 0 deletions test/unit/dump_database.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
setup() {
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR/../../src:$DIR/../../src/lib:$PATH"
source db.sh

wait_for_database "database" "3306" "root" "root" "60"
}

teardown() {
run bash -c "rm -f /tmp/backup/*"
}

@test "fails if no argument given" {
run dump_database
[ "$status" -eq 1 ]
[ "$output" = "5 arguments required, 0 provided" ]
}

@test "dumps a database" {
run dump_database "database" "3306" "root" "root" "my_db"
[ "$status" -eq 0 ]
[ -f "/tmp/backup/my_db.sql" ]
[[ "$(head -n1 "/tmp/backup/my_db.sql")" = *"-- MariaDB dump"* ]]
}
6 changes: 3 additions & 3 deletions test/unit/get_archive_name.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ setup() {
source file.sh

shopt -s expand_aliases
alias date="faketime '2022/01/05 06:35:46' date"
alias date="FAKETIME='2022-01-05 06:35:46' date"

run get_archive_name "main-backup"
echo "$output"
Expand All @@ -27,7 +27,7 @@ setup() {
source file.sh

shopt -s expand_aliases
alias date="faketime '2022/02/19 12:54:11' date"
alias date="FAKETIME='2022-02-19 12:54:11' date"

run get_archive_name "main-backup"
echo "$output"
Expand All @@ -39,7 +39,7 @@ setup() {
source file.sh

shopt -s expand_aliases
alias date="faketime '2022/02/28 18:43:24' date"
alias date="FAKETIME='2022-02-28 18:43:24' date"

run get_archive_name "main-backup"
[ "$status" -eq 0 ]
Expand Down
Loading

0 comments on commit ca72be2

Please sign in to comment.