load common begin_backupninja() { install_pkgs prometheus-node-exporter } teardown_backupninja() { [ -x /usr/bin/mail.moved ] && mv /usr/bin/mail.moved /usr/bin/mail [ -x /usr/bin/rsync.moved ] && mv /usr/bin/rsync.moved /usr/bin/rsync rm -f /var/mail/vagrant rm -f /var/lib/prometheus/node-exporter/backupninja.prom } create_test_action() { echo '#!/bin/sh' > "${BATS_TMPDIR}/backup.d/test.sh" echo "$1 $2" >> "${BATS_TMPDIR}/backup.d/test.sh" chmod 0750 "${BATS_TMPDIR}/backup.d/test.sh" } @test "general: usage information is displayed" { run backupninja --help [ "$status" -eq 0 ] [ "${lines[0]}" = "/usr/sbin/backupninja usage:" ] } @test "general: error thrown on bad command-line option" { run backupninja --foo [ "$status" -eq 3 ] echo "${lines[0]}" | grep -q "Error: Unknown option --foo" } @test "general: error thrown on attempt to run as non-root user" { run sudo -u vagrant backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 3 ] [ "${lines[1]}" = "backupninja can only be run as root" ] } @test "general: logfile is created" { run backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] [ -f "${BATS_TMPDIR}/log/backupninja.log" ] } @test "general: no backup actions configured is logged" { run backupninja --test -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] [ "${lines[0]}" = "Info: No backup actions configured in '${BATS_TMPDIR}/backup.d', run ninjahelper!" ] } @test "general: file without suffix in action directory is ignored" { touch "${BATS_TMPDIR}/backup.d/test" chmod 0640 "${BATS_TMPDIR}/backup.d/test" run backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Info: Skipping ${BATS_TMPDIR}/backup.d/test" "${BATS_TMPDIR}/log/backupninja.log" } @test "permissions: error thrown when backup action is owned by non-root user" { create_test_action chown vagrant: "${BATS_TMPDIR}/backup.d/test.sh" run backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 2 ] echo "${lines[0]}" | grep -qe '^Configuration files must be owned by root!' } @test "permissions: error thrown when backup action is world readable" { create_test_action chmod 0755 "${BATS_TMPDIR}/backup.d/test.sh" run backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 2 ] echo "${lines[0]}" | grep -qe '^Configuration files must not be world writable/readable!' } @test "permissions: error thrown when backup action group ownership is bad" { create_test_action chgrp staff "${BATS_TMPDIR}/backup.d/test.sh" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 2 ] echo "${lines[0]}" | grep -qe '^Configuration files must not be writable/readable by group staff!' } @test "permissions: admingroup allows non-root group ownership of backup action" { create_test_action setconfig backupninja.conf admingroup staff chgrp staff "${BATS_TMPDIR}/backup.d/test.sh" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] } @test "reports: report is mailed when halts > 0" { create_test_action halt test_halt run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "\*halt\* -- ${BATS_TMPDIR}/backup.d/test.sh" /var/mail/vagrant } @test "reports: report is mailed when fatals > 0" { create_test_action fatal test_error run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "\*failed\* -- ${BATS_TMPDIR}/backup.d/test.sh" /var/mail/vagrant } @test "reports: report is mailed when reportwarning = yes and warnings > 0" { create_test_action warning test_warning setconfig backupninja.conf reportsuccess no setconfig backupninja.conf reportwarning yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "Warning: test_warning" /var/mail/vagrant } @test "reports: report is mailed when reportsuccess = yes" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "success -- ${BATS_TMPDIR}/backup.d/test.sh" /var/mail/vagrant } @test "reports: success report contains informational messages" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "Info: test_info" /var/mail/vagrant } @test "reports: success report contains disk space info" { create_test_action info test_info echo "directory = /" >> "${BATS_TMPDIR}/backup.d/test.sh" setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportspace yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q "/dev/sda1" /var/mail/vagrant } @test "reports: emits error if mail executable is not found" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes mv /usr/bin/mail /usr/bin/mail.moved run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: wraps report text to 1000 columns by default" { create_test_action info "$(printf \'=%.0s\' {1..2000})" setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q '^=\{1000\}$' /var/mail/vagrant } @test "reports: wraps report text according to reportwrap" { create_test_action info "$(printf \'=%.0s\' {1..2000})" setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reportwrap 100 run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" sleep 0.1 grep -q '^=\{100\}$' /var/mail/vagrant } @test "reports: reporthost sends report to remote host" { cleanup_backups remote create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportuser "$BN_REMOTEUSER" setconfig backupninja.conf reportdirectory "$BN_BACKUPDIR" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 0 ] ssh "${BN_REMOTEUSER}@${BN_REMOTEHOST}" test -s "${BN_BACKUPDIR}/backupninja.log" } @test "reports: emits error when reportuser is empty" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportdirectory "$BN_BACKUPDIR" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: emits error when reportdirectory is empty" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportuser "$BN_REMOTEUSER" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: emits error when rsync is not found" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportuser "$BN_REMOTEUSER" mv /usr/bin/rsync /usr/bin/rsync.moved run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: emits error when reporthost is invalid" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost foo setconfig backupninja.conf reportuser "$BN_REMOTEUSER" setconfig backupninja.conf reportdirectory "$BN_BACKUPDIR" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: emits error when reportuser is invalid" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportuser foo setconfig backupninja.conf reportdirectory "$BN_BACKUPDIR" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: emits error when reportdirectory is unwritable" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reporthost "$BN_REMOTEHOST" setconfig backupninja.conf reportuser "$BN_REMOTEUSER" setconfig backupninja.conf reportdirectory "/foo" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "reports: email not sent when reportemail is no" { create_test_action info test_info setconfig backupninja.conf reportsuccess yes setconfig backupninja.conf reportinfo yes setconfig backupninja.conf reportemail no run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 0 ] ! test -f /var/mail/vagrant } @test "reports: writes prometheus metrics when reportprom is yes" { create_test_action info test_info setconfig backupninja.conf reportprom yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 0 ] grep -q "^backupninja_actions{host=\"$(hostname)\"} 1$" /var/lib/prometheus/node-exporter/backupninja.prom } @test "scheduling: runs when = 'everyday at 01' and time matches" { create_test_action info test_info setconfig backupninja.conf when 'everyday at 01' run faketime -f '@2018-06-12 01:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Info: FINISHED: 1 actions run. 0 fatal. 0 error. 0 warning." "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: skips when = 'everyday at 01' and time is mismatched" { create_test_action info test_info setconfig backupninja.conf when 'everyday at 01' run faketime -f '@2018-06-12 02:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Debug: skipping ${BATS_TMPDIR}/backup.d/test.sh because current time does not match everyday at 01" "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: runs when = 'Tuesday at 04' and time matches" { create_test_action info test_info setconfig backupninja.conf when 'Tuesday at 04' run faketime -f '@2018-06-12 04:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Info: FINISHED: 1 actions run. 0 fatal. 0 error. 0 warning." "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: skips when = 'Tuesday at 04' and time is mismatched" { create_test_action info test_info setconfig backupninja.conf when 'Tuesday at 04' run faketime -f '@2018-06-13 04:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Debug: skipping ${BATS_TMPDIR}/backup.d/test.sh because current time does not match Tuesday at 04" "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: runs when = '1st at 10' and time matches" { create_test_action info test_info setconfig backupninja.conf when '1st at 10' run faketime -f '@2018-06-01 10:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Info: FINISHED: 1 actions run. 0 fatal. 0 error. 0 warning." "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: skips when = '1st at 10' and time is mismatched" { create_test_action info test_info setconfig backupninja.conf when '1st at 10' run faketime -f '@2018-06-15 10:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Debug: skipping ${BATS_TMPDIR}/backup.d/test.sh because current time does not match 1st at 10" "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: runs when = '21 at 09:00' and time matches" { create_test_action info test_info setconfig backupninja.conf when '21 at 09:00' run faketime -f '@2018-06-21 09:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Info: FINISHED: 1 actions run. 0 fatal. 0 error. 0 warning." "${BATS_TMPDIR}/log/backupninja.log" } @test "scheduling: skips when = '21 at 09:00' and time is mismatched" { create_test_action info test_info setconfig backupninja.conf when '21 at 09:00' run faketime -f '@2018-06-22 09:00:00' backupninja -f "${BATS_TMPDIR}/backupninja.conf" [ "$status" -eq 0 ] grep -q "Debug: skipping ${BATS_TMPDIR}/backup.d/test.sh because current time does not match 21 at 09:00" "${BATS_TMPDIR}/log/backupninja.log" } @test "exit code: rc=2 when halt error raised in handler" { create_test_action halt test_halt run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 2 ] } @test "exit code: rc=2 when fatal error raised in handler" { create_test_action fatal test_fatal run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 2 ] } @test "exit code: rc=1 when error raised in handler" { create_test_action error test_error run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "exit code: rc=1 when warning raised in handler and reportwarning=yes" { create_test_action warning test_warning setconfig backupninja.conf reportwarning yes run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 1 ] } @test "exit code: rc=0 when warning raised in handler and reportwarning=no" { create_test_action warning test_warning setconfig backupninja.conf reportwarning no run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 0 ] } @test "exit code: rc=0 when no warnings/errors raised in handler" { create_test_action "true" run backupninja --now -f "${BATS_TMPDIR}/backupninja.conf" --run "${BATS_TMPDIR}/backup.d/test.sh" [ "$status" -eq 0 ] }