#!/usr/bin/env bash
set -e

# ----------------------------------------------------------------------
# File: eos-timestamp-test
# Author: Aritz Brosa Iartza - CERN
#         Mihai Patrascoiu - CERN
# ----------------------------------------------------------------------

# ******************************************************************************
# EOS - the CERN Disk Storage System
# Copyright (C) 2020 CERN/Switzerland
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ******************************************************************************

#------------------------------------------------------------------------------
# Description: Script testing timestamp functionality of EOS.
#              The following test scenarios are executed:
#                - File is created     => mtime, ctime and btime are identical
#                - Content is modified => mtime and ctime change
#                - Metadata is changed => only ctime changes
#                - Touch is performed  => mtime and ctime change
#
# Usage: eos-timestamp-test <eos_instance_name> [<eos_mgm_hostname>]
#------------------------------------------------------------------------------

# Global timestamp variables used by utility function
mtime=0
ctime=0
btime=0

# Global return code
rc=0

#------------------------------------------------------------------------------
# Helper functions
#------------------------------------------------------------------------------

function usage() {
  echo "Usage: $0 <eos_instance_name> [<eos_mgm_hostname>]"
  echo "       <eos_instance_name> - the /eos/<instance_name>/ to access"
  echo "       <eos_mgm_hostname>  - optional MGM hostname (will use EOS_MGM_URL env variable otherwise)"
  echo ""

  exit 1
}

function retrieve_timestamps() {
  local fileinfo=`eos -j fileinfo $1`
  
  mtime=`echo ${fileinfo} | jq '(.mtime|tostring) + "." + (.mtime_ns|tostring)'`
  ctime=`echo ${fileinfo} | jq '(.ctime|tostring) + "." + (.ctime_ns|tostring)'`
  btime=`echo ${fileinfo} | jq '(.btime|tostring) + "." + (.btime_ns|tostring)'`

  echo "mtime=${mtime} ctime=${ctime} btime=${btime}"
}

#------------------------------------------------------------------------------
# Global setup
#------------------------------------------------------------------------------

if [[ $# -eq 0 || $# -gt 2 ]]; then
  usage
fi

# Setup EOS instance variables
EOS_INSTANCE_NAME=$1
EOS_MGM_HOSTNAME=$2

if [[ -z "$EOS_MGM_HOSTNAME" ]]; then
  if [[ -n "$EOS_MGM_URL" ]]; then
    EOS_MGM_HOSTNAME=${EOS_MGM_URL#root://}
    EOS_MGM_HOSTNAME=${EOS_MGM_HOSTNAME%:1094/}
  else
    EOS_MGM_HOSTNAME=localhost
  fi
fi

export EOS_MGM_URL=${EOS_MGM_HOSTNAME}
echo "EOS_INSTANCE_NAME=${EOS_INSTANCE_NAME}"
echo "EOS_MGM_HOSTNAME=${EOS_MGM_HOSTNAME}"

#------------------------------------------------------------------------------
# Testing scenario
#------------------------------------------------------------------------------

# Initial setup
eos mkdir -p /eos/${EOS_INSTANCE_NAME}/timestamp_tests/
touch /eos1/${EOS_INSTANCE_NAME}/timestamp_tests/file

printf "\nRetrieving initial timestamps\n"
retrieve_timestamps /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file
mtime_init=$mtime
ctime_init=$ctime
btime_init=$btime

# TEST: All timestamps should be identical
# Note: Compare only the integer part of the timestamp for birthtime
#       (btime has a slight btime_ns difference)
if [[ ${mtime_init} != ${ctime_init} || ${mtime_init%.*} != ${btime_init%.*} ]]; then
  echo "Timestamps are not equal after test file creation" >&2
  rc=1
fi

## File content modification scenario
sleep 1
printf "\nRetrieving timestamps after content modification\n"
echo 'start' > /eos1/${EOS_INSTANCE_NAME}/timestamp_tests/file
retrieve_timestamps /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file
mtime_cont=$mtime
ctime_cont=$ctime
btime_cont=$btime

# TEST: Content modification should affect mtime and ctime
if [[ ${mtime_init} == ${mtime_cont} || ${ctime_init} == ${ctime_cont} || ${btime_init} != ${btime_cont} ]]; then
  echo "Content modification timestamps not behaving as expected" >&2
  if [[ ${mtime_init} == ${mtime_cont} ]]; then echo "-- mtime did not change" >&2 ; fi
  if [[ ${ctime_init} == ${ctime_cont} ]]; then echo "-- ctime did not change" >&2 ; fi
  if [[ ${btime_init} != ${btime_cont} ]]; then echo "-- btime changed but it should not have" >&2 ; fi
  rc=1
fi

## File metadata change scenario
sleep 1
printf "\nRetrieving timestamps after metadata-only modification\n"
eos attr set user.eos.dummy="value" /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file
retrieve_timestamps /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file
mtime_metad=$mtime
ctime_metad=$ctime
btime_metad=$btime

# TEST: Metadata-only change should affect only ctime
if [[ ${mtime_cont} != ${mtime_metad} || ${ctime_cont} == ${ctime_metad} || ${btime_cont} != ${btime_metad} ]]; then
  echo "Metadata modification timestamps not behaving as expected" >&2
  if [[ ${mtime_cont} != ${mtime_metad} ]]; then echo "-- mtime changed but it should not have" >&2 ; fi
  if [[ ${ctime_cont} == ${ctime_metad} ]]; then echo "-- ctime did not change" >&2 ; fi
  if [[ ${btime_cont} != ${btime_metad} ]]; then echo "-- btime changed but it should not have" >&2 ; fi
  rc=1
fi

## Touch scenario
sleep 1
printf "\nRetrieving timestamps after touch\n"
eos touch /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file > /dev/null
retrieve_timestamps /eos/${EOS_INSTANCE_NAME}/timestamp_tests/file
mtime_touch=$mtime
ctime_touch=$ctime
btime_touch=$btime

# TEST: Touch should affect mtime and ctime
if [[ ${mtime_metad} == ${mtime_touch} || ${ctime_metad} == ${ctime_touch} || ${btime_metad} != ${btime_touch} ]]; then
  echo "Touch command timestamps not behaving as expected" >&2
  if [[ ${mtime_metad} == ${mtime_touch} ]]; then echo "-- mtime did not change" >&2 ; fi
  if [[ ${ctime_metad} == ${ctime_touch} ]]; then echo "-- ctime did not change" >&2 ; fi
  if [[ ${btime_metad} != ${btime_touch} ]]; then echo "-- btime changed but it should not have" >&2 ; fi
  rc=1
fi

# Clean-up
eos rm /eos/dockertest/timestamp_tests/*
eos rmdir /eos/dockertest/timestamp_tests/
exit ${rc}
