#!/bin/bash

# BAREOS - Backup Archiving REcovery Open Sourced
#
# Copyright (C) 2025-2026 Benjamin Somers, IMT Atlantique
# Copyright (C) 2025-2026 Bareos GmbH & Co. KG
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of version three of the GNU Affero General Public
# License as published by the Free Software Foundation, which is
# listed in the file LICENSE.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

set -euo pipefail
#
# This systemtest tests the Incus FD plugin
#

TestName="$(basename "$(pwd)")"
export TestName

JobName=backup-incus-vm
#shellcheck source=../../environment.in
. ./environment

export PATH="$current_test_directory/sbin:$current_test_directory/bin:$PATH"

JobName=backup-incus-vm
#shellcheck source=../../scripts/functions
. "${BAREOS_SCRIPTS_DIR}"/functions

INSTANCE="${INCUS_VM_NAME}"
NEWINSTANCE="${INSTANCE}"-restored

wait_for_agent()
{
  while ! incus exec "$1" true 2>/dev/null; do
    sleep 2
  done
}

sync_fs()
{
  incus exec "${INSTANCE}" sync
}

cleanup_instances()
{
  echo "cleaning up ..." >&2
  incus rm -f "${INSTANCE}" 2>/dev/null || :
  incus rm -f "${NEWINSTANCE}" 2>/dev/null || :
}

check_chunks()
{
  grep -c "^ @INCUS/instances/$2" "$1" || :
}

trap cleanup_instances EXIT

cleanup_instances

echo "creating ${INSTANCE} ..." >&2
incus launch "${INCUS_VM_BASE_NAME}" "${INSTANCE}" --vm -c security.secureboot=false -d root,size=400MiB
wait_for_agent "${INSTANCE}"
incus file push - "${INSTANCE}/old-file" <<<"foobar"
sync_fs

start_test

cat <<END_OF_DATA >$tmp/bconcmds
@#
@# First, perform a full backup
@#
@$out $NULL_DEV
messages
@$out ${runner_tmp}/full.out
label volume=TestVolume003 storage=File pool=Full
run job=$JobName level=Full yes
status director
status client
status storage=File
wait
messages
END_OF_DATA

run_bconsole "$@"
check_log "${runner_tmp}/full.out"

cat <<END_OF_DATA >$tmp/bconcmds
@$out ${runner_tmp}/full-list.out
list files jobid=$(last_jobid_or_zero)
END_OF_DATA
run_bconsole "$@"

# 25 chunks should be created here
chunks="$(check_chunks "${runner_tmp}/full-list.out" "${INSTANCE}/virtual-machine.img")"
if ((chunks != 25)); then
  echo "Error: expected 25 chunks, got $chunks"
  exit 1
fi

echo "pushing new file to ${INSTANCE} ..." >&2
incus file push - "${INSTANCE}/new-file" <<<"bazqux"
sync_fs

cat <<END_OF_DATA >$tmp/bconcmds
@#
@# Then, perform an incremental backup to get the new file
@#
@$out ${runner_tmp}/incr.out
label volume=TestVolume004 storage=File pool=Incremental
run job=$JobName level=Incremental yes
status director
status client
status storage=File
wait
messages
END_OF_DATA

run_bconsole "$@"
check_log "${runner_tmp}/incr.out"

cat <<END_OF_DATA >$tmp/bconcmds
@$out ${runner_tmp}/incr-list.out
list files jobid=$(last_jobid_or_zero)
END_OF_DATA
run_bconsole "$@"

# Modifying our single file should only modify ~4 chunks, but let's be safe
chunks="$(check_chunks "${runner_tmp}/incr-list.out" "${INSTANCE}/virtual-machine.img")"
if ((chunks > 8)); then
  echo "Error: too many chunks modified ($chunks)"
  exit 1
fi

echo "removing ${INSTANCE} ..." >&2
incus rm -f "${INSTANCE}"

cat <<END_OF_DATA >$tmp/bconcmds
@#
@# Now, restore the incremental backup to a new instance
@#
@$out ${runner_tmp}/restore.out
wait
restore client=bareos-fd fileset=IncusTestVM where=/ select all done pluginoptions=python:restore_instance=${NEWINSTANCE}
yes
wait
messages
END_OF_DATA

run_bconsole "$@"
check_log "${runner_tmp}/restore.out"

echo "starting ${NEWINSTANCE} ..." >&2
incus start "${NEWINSTANCE}"
wait_for_agent "${NEWINSTANCE}"

if [ "$(incus file pull "${NEWINSTANCE}/old-file" -)" = "foobar" ] \
  && [ "$(incus file pull "${NEWINSTANCE}/new-file" -)" = "bazqux" ]; then
  echo "Restored files OK"
else
  echo "Restored files ERROR: files have changed"
  dstat=1
  exit 1
fi

echo "removing ${NEWINSTANCE} ..." >&2
incus rm -f "${NEWINSTANCE}"

check_for_zombie_jobs storage=File

end_test
