#!/bin/bash
cvmfs_test_name="Server Infrastructure Mounting"
cvmfs_test_autofs_on_startup=false
cvmfs_test_suites="quick"

set_auto_repair() {
  local name="$1"
  local value="$2"

  local server_conf="/etc/cvmfs/repositories.d/${name}/server.conf"
  if cat $server_conf | grep -q "CVMFS_AUTO_REPAIR_MOUNTPOINT"; then
    sudo sed -i -e \
      "s/^\(CVMFS_AUTO_REPAIR_MOUNTPOINT\)=.*$/\1=${value}/" $server_conf
  else
    echo "CVMFS_AUTO_REPAIR_MOUNTPOINT=${value}" \
      | sudo tee --append $server_conf
  fi
}

disable_auto_repair() {
  local name="$1"
  set_auto_repair $name "false"
}

enable_auto_repair() {
  local name="$1"
  set_auto_repair $name "true"
}

CVMFS_TEST_630_REPLICA_NAME=
CVMFS_TEST_630_REPO2_NAME=
cleanup() {
  echo "running cleanup()..."
  [ -z $CVMFS_TEST_630_REPLICA_NAME ] || sudo cvmfs_server rmfs -f $CVMFS_TEST_630_REPLICA_NAME
  [ -z $CVMFS_TEST_630_REPO2_NAME   ] || sudo cvmfs_server rmfs -f $CVMFS_TEST_630_REPO2_NAME
}

cvmfs_run_test() {
  logfile=$1
  local repo_dir=/cvmfs/$CVMFS_TEST_REPO
  local scratch_dir=$(pwd)

  echo "create a fresh repository named $CVMFS_TEST_REPO with user $CVMFS_TEST_USER"
  create_empty_repo $CVMFS_TEST_REPO $CVMFS_TEST_USER || return $?

  echo "pull in repository configuration"
  load_repo_config $CVMFS_TEST_REPO || return 1
  local rdonly_dir="$(readlink -e "${CVMFS_SPOOL_DIR}/rdonly")"

  echo "make sure that CVMFS_AUTO_REPAIR_MOUNTPOINT=true"
  [ x"$CVMFS_AUTO_REPAIR_MOUNTPOINT" != x"false" ] || return 100

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Check standard mount of unmounted repository outside of transaction

  echo "Unmount $CVMFS_TEST_REPO"
  cvmfs_suid_helper rw_umount     $CVMFS_TEST_REPO || return 2
  cvmfs_suid_helper rdonly_umount $CVMFS_TEST_REPO || return 3

  echo "Check that the repository is properly unmounted"
  cat /proc/mounts | grep -e " $repo_dir "   && return 4
  cat /proc/mounts | grep -e " $rdonly_dir " && return 5

  echo "Mount the repository using cvmfs_server"
  cvmfs_server mount $CVMFS_TEST_REPO || return 6

  echo "Check that the repository is properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "   || return 7
  cat /proc/mounts | grep -e " $rdonly_dir " || return 8

  echo "check catalog and data integrity"
  check_repository $CVMFS_TEST_REPO -i  || return $?

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Check mount of unmounted repository during transaction

  echo "open transaction"
  start_transaction $CVMFS_TEST_REPO || return 9

  echo "Unmount $CVMFS_TEST_REPO"
  cvmfs_suid_helper rw_umount     $CVMFS_TEST_REPO || return 10
  cvmfs_suid_helper rdonly_umount $CVMFS_TEST_REPO || return 11

  echo "Check that the repository is properly unmounted"
  cat /proc/mounts | grep -e " $repo_dir "   && return 12
  cat /proc/mounts | grep -e " $rdonly_dir " && return 13

  echo "Mount the repository using cvmfs_server"
  cvmfs_server mount $CVMFS_TEST_REPO || return 14

  echo "Check that the repository is properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "          || return 15
  cat /proc/mounts | grep -e " $rdonly_dir "        || return 16
  cat /proc/mounts | grep -e " ${repo_dir}.*rw[ ,]" || return 17

  echo "publish repository"
  publish_repo $CVMFS_TEST_REPO || return 18

  echo "check catalog and data integrity"
  check_repository $CVMFS_TEST_REPO -i  || return $?

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Check mounting rdonly-branch of repository during transaction

  echo "open transaction"
  start_transaction $CVMFS_TEST_REPO || return 19

  echo "Unmount $CVMFS_TEST_REPO (rdonly only)"
  cvmfs_suid_helper rw_umount     $CVMFS_TEST_REPO || return 20
  cvmfs_suid_helper rdonly_umount $CVMFS_TEST_REPO || return 21
  cvmfs_suid_helper rw_mount      $CVMFS_TEST_REPO || return 22

  echo "Check that the repository is properly unmounted"
  cat /proc/mounts | grep -e " $repo_dir "   || return 23
  cat /proc/mounts | grep -e " $rdonly_dir " && return 24

  echo "Mount the repository using cvmfs_server"
  cvmfs_server mount $CVMFS_TEST_REPO || return 25

  echo "Check that the repository is properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "          || return 26
  cat /proc/mounts | grep -e " $rdonly_dir "        || return 27
  cat /proc/mounts | grep -e " ${repo_dir}.*rw[ ,]" || return 28

  echo "publish repository"
  publish_repo $CVMFS_TEST_REPO || return 29

  echo "check catalog and data integrity"
  check_repository $CVMFS_TEST_REPO -i  || return $?

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Check mounting repository with CVMFS_AUTO_REPAIR_MOUNTPOINT=false

  echo "set CVMFS_AUTO_REPAIR_MOUNTPOINT=false"
  disable_auto_repair $CVMFS_TEST_REPO || return 31

  echo "Unmount $CVMFS_TEST_REPO"
  cvmfs_suid_helper rw_umount     $CVMFS_TEST_REPO || return 32
  cvmfs_suid_helper rdonly_umount $CVMFS_TEST_REPO || return 33

  echo "Check that the repository is properly unmounted"
  cat /proc/mounts | grep -e " $repo_dir "   && return 34
  cat /proc/mounts | grep -e " $rdonly_dir " && return 35

  echo "Mount the repository using cvmfs_server"
  cvmfs_server mount $CVMFS_TEST_REPO || return 36

  echo "Check that the repository is properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "   || return 37
  cat /proc/mounts | grep -e " $rdonly_dir " || return 38

  echo "check catalog and data integrity"
  check_repository $CVMFS_TEST_REPO -i  || return $?

  echo "set CVMFS_AUTO_REPAIR_MOUNTPOINT=true"
  enable_auto_repair $CVMFS_TEST_REPO || return 39

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Create more repositories and Stratum1s to check `cvmfs_server mount -a`

  echo "install a cleanup function"
  trap cleanup EXIT HUP INT TERM

  echo "create Stratum1 repository on the same machine"
  load_repo_config $CVMFS_TEST_REPO
  local replica_name="$(get_stratum1_name $CVMFS_TEST_REPO)"
  CVMFS_TEST_630_REPLICA_NAME=$replica_name
  create_stratum1 $replica_name                          \
                  $CVMFS_TEST_USER                       \
                  $CVMFS_STRATUM0                        \
                  /etc/cvmfs/keys/${CVMFS_TEST_REPO}.pub || return 40

  echo "initial snapshot into $replica_name"
  cvmfs_server snapshot $replica_name || return 41

  local repo2="${CVMFS_TEST_REPO}.$(date +%s%N | sha1sum | head -c6)"
  echo "create a second Stratum0 ($repo2) owned by $CVMFS_TEST_USER"
  CVMFS_TEST_630_REPO2_NAME=$repo2
  create_repo $repo2 $CVMFS_TEST_USER || return 42

  echo "pull in repository configuration for $repo2"
  load_repo_config $repo2 || return 43
  local repo2_repo_dir="/cvmfs/${repo2}"
  local repo2_rdonly_dir="$(readlink -e "${CVMFS_SPOOL_DIR}/rdonly")"

  echo -n "check if there are more repositories than expected... "
  local repo_count=$(cvmfs_server list | wc -l)
  if [ $repo_count -eq 3 ]; then
    echo "no"
  else
    echo "yes ($repo_count repos found)"
    cvmfs_server list
    echo "WARNING: THIS MIGHT AFFECT THE OUTCOME OF THE NEXT TESTS..."
    CVMFS_GENERAL_WARNING_FLAG=1
  fi

  echo "Check that the repositories are properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "         || return 44
  cat /proc/mounts | grep -e " $rdonly_dir "       || return 45
  cat /proc/mounts | grep -e " $repo2_repo_dir "   || return 46
  cat /proc/mounts | grep -e " $repo2_rdonly_dir " || return 47

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Run `cvmfs_server mount -a` with all repos properly mounted

  if [ x"$(whoami)" != x"root" ]; then
    local mount_log_1="$(pwd)/mount_1.log"
    echo "run \`cvmfs_server mount -a\` without necessity and as non-root (log: $mount_log_1)"
    cvmfs_server mount -a > $mount_log_1 2>&1 && return 48

    echo "check error message"
    cat $mount_log_1 | grep 'need root to mount all' || return 49
  else
    echo "WARNING: cannot test non-root behaviour of \`cvmfs_server mount -a\` as root"
    CVMFS_GENERAL_WARNING_FLAG=1
  fi

  echo "do \`cvmfs_server mount -a\` without necessity"
  sudo cvmfs_server mount -a || return 50

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Run `cvmfs_server mount -a` with mount problems in the repositories

  echo "break mounts for the repositories (umount rdonly for $CVMFS_TEST_REPO)"
  cvmfs_suid_helper rw_umount     $CVMFS_TEST_REPO || return 51
  cvmfs_suid_helper rdonly_umount $CVMFS_TEST_REPO || return 52
  cvmfs_suid_helper rw_mount      $CVMFS_TEST_REPO || return 53

  echo "open transaction for $repo2"
  start_transaction $repo2 || return 54

  echo "break mounts for the repositories (umount rdonly for $repo2 and make union read-only)"
  cvmfs_suid_helper rw_umount     $repo2 || return 55
  cvmfs_suid_helper rdonly_umount $repo2 || return 56
  cvmfs_suid_helper rw_mount      $repo2 || return 57

  echo "Check that the repositories are not properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "         || return 58
  cat /proc/mounts | grep -e " $rdonly_dir "       && return 59
  cat /proc/mounts | grep -e " $repo2_repo_dir "   || return 60
  cat /proc/mounts | grep -e " $repo2_rdonly_dir " && return 61

  echo "do \`cvmfs_server mount -a\` to bring all repositories back into proper shape"
  sudo cvmfs_server mount -a || return 62

  echo "Check that the repositories are properly mounted"
  cat /proc/mounts | grep -e " $repo_dir "         || return 63
  cat /proc/mounts | grep -e " $rdonly_dir "       || return 64
  cat /proc/mounts | grep -e " $repo2_repo_dir "   || return 65
  cat /proc/mounts | grep -e " $repo2_rdonly_dir " || return 66

  echo "publish $repo2"
  publish_repo $repo2 || return 67

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # Provoke a mount failure for a multi-repo `cvmfs_server mount`

  echo "break union fs mount point of ${CVMFS_TEST_REPO} and ${repo2}"
  cvmfs_suid_helper rw_umount $CVMFS_TEST_REPO || return 68
  cvmfs_suid_helper rw_umount $repo2           || return 69

  echo "remove ${repo2_repo_dir} to provoke failed mount call"
  sudo rm -fR $repo2_repo_dir || return 70
  sudo touch $repo2_repo_dir || return 70

  echo "check that both $repo_dir and $repo2_repo_dir are not mounted"
  cat /proc/mounts | grep -e " $repo_dir "         && return 71
  cat /proc/mounts | grep -e " $repo2_repo_dir "   && return 72

  local mount_log_2="$(pwd)/mount_2.log"
  echo "try to mount ${CVMFS_TEST_REPO} and $repo2 (should fail | log: ${mount_log_2})"
  cvmfs_server mount $CVMFS_TEST_REPO $repo2 > $mount_log_2 2>&1 && return 73

  echo "check that an error message was printed"
  cat $mount_log_2 | grep 'Trying to mount.*fail' || return 74

  echo "check that $repo_dir is mounted but $repo2_repo_dir is still not"
  cat /proc/mounts | grep -e " $repo_dir "         || return 75
  cat /proc/mounts | grep -e " $repo2_repo_dir "   && return 76

  echo "repair the mount point"
  sudo rm $repo2_repo_dir || return 77
  sudo mkdir -p $repo2_repo_dir || return 77

  echo "try to mount again (should work now)"
  cvmfs_server mount $CVMFS_TEST_REPO || return 78

  return 0
}

