timescaledb/scripts/test_update_smoke.sh
Markos Fountoulakis fab16f3798 Fix segfault in Continuous Aggregates
Add the missing variables to the finalization view of Continuous
Aggregates and the corresponding columns to the materialization table.
Cover the case of targets that contain Aggref nodes and Var nodes
that are outside of the Aggref nodes at the same time.

Stop rebuilding the Continuous Aggregate view with ALTER MATERIALIZED
VIEW. Attempt to repair the view at post-update time instead, and fail
gracefully if it is not possible to do so without raw hypertable schema
or data modifications.

Stop rebuilding the Continuous Aggregate view when switching realtime
aggregation on and off. Instead, manipulate the User View by either:
  1. removing the UNION ALL right-hand side and the WHERE clause when
     disabling realtime aggregation
  2. adding the Direct View to the right of a UNION ALL operator and
     defining WHERE clauses with the relevant watermark checks when
     enabling realtime aggregation

Fixes #3898
2022-04-18 12:54:20 +03:00

209 lines
7.1 KiB
Bash
Executable File

#!/bin/bash
# shellcheck disable=SC2129,SC2230
# SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
# SC2230: which is non-standard. Use builtin 'command -v' instead.
# Run smoke tests to test that updating between versions work.
#
# Usage:
# bash test_update_smoke.sh postgres://...
#
# This is based on our update tests but doing some tweaks to ensure we
# can run it on Forge (or any other PostgreSQL server that only permit
# a single user and single database).
#
# In particular, we cannot create new roles and we cannot create new
# databases.
#
# For this version, we focus on single-node update and smoke testing
# cannot (necessarily) be done with multinode setups. Feel free to try
# though.
#
# The following environment variables can be set:
# - UPDATE_FROM_TAG is the version to update from (optional).
#
# - UPDATE_TO_TAG is the version to update to (optional).
#
# - PGHOST is host to use for the connection (required).
#
# - PGPORT is the port to use for the connection (required).
#
# - PGDATABASE is the database to use for the connection (required).
#
# - PGUSER is the username to use for the connection (required).
#
# - PGPASSWORD is the password to use for the connection
# (optional). If not set, password from .pgpass will be used (if
# available).
SCRIPT_DIR=$(dirname $0)
BASE_DIR=${PWD}/${SCRIPT_DIR}/..
SCRATCHDIR=$(mktemp -d -t 'smoketest-XXXX')
LOGFILE="$SCRATCHDIR/update-test.log"
DUMPFILE="$SCRATCHDIR/smoke.dump"
UPGRADE_OUT="$SCRATCHDIR/upgrade.out"
CLEAN_OUT="$SCRATCHDIR/clean.out"
RESTORE_OUT="$SCRATCHDIR/restore.out"
TEST_VERSION=${TEST_VERSION:-v7}
UPDATE_FROM_TAG=${UPDATE_FROM_TAG:-1.7.4}
UPDATE_TO_TAG=${UPDATE_TO_TAG:-2.0.1}
# We do not have superuser privileges when running smoke tests.
WITH_SUPERUSER=false
WITH_ROLES=false
while getopts "ds:t:" opt;
do
case $opt in
d)
cleanup=1
;;
s)
UPDATE_FROM_TAG=$OPTARG
;;
t)
UPDATE_TO_TAG=$OPTARG
;;
*)
;;
esac
done
shift $((OPTIND-1))
echo "**** pg_dump at " "$(which pg_dump)"
echo "**** pg_restore at" "$(which pg_restore)"
# Extra options to pass to psql
PGOPTS="-v TEST_VERSION=${TEST_VERSION} -v WITH_SUPERUSER=${WITH_SUPERUSER} -v WITH_ROLES=${WITH_ROLES} -v WITH_CHUNK=false"
PSQL="psql -qX $PGOPTS"
# If we are providing a URI for the connection, we parse it here and
# set the PG??? variables since that is the only reliable way to
# provide connection information to psql, pg_dump, and pg_restore.
#
# To work with Forge, we need to only set PGPASSWORD when the password
# is available and leave it unset otherwise. If the user has either
# set PGPASSWORD or has the password in a .pgpass file, it will be
# picked up and used for the connection.
if [[ $# -gt 0 ]]; then
# shellcheck disable=SC2207 # Prefer mapfile or read -a to split command output (or quote to avoid splitting).
parts=($(echo $1 | perl -mURI::Split=uri_split -ne '@F = uri_split($_); print join(" ", split(qr/[:@]/, $F[1]), substr($F[2], 1))'))
export PGUSER=${parts[0]}
if [[ ${#parts[@]} -eq 5 ]]; then
# Cloud has 5 fields
export PGPASSWORD=${parts[1]}
export PGHOST=${parts[2]}
export PGPORT=${parts[3]}
export PGDATABASE=${parts[4]}
elif [[ ${#parts[@]} -eq 4 ]]; then
# Forge has 4 fields
export PGHOST=${parts[1]}
export PGPORT=${parts[2]}
export PGDATABASE=${parts[3]}
else
echo "Malformed URL '$1'" 1>&2
exit 2
fi
fi
cleanup() {
rm -rf $SCRATCHDIR
}
if [[ "x$cleanup" != "x" ]]; then
echo "**** Debug mode: $SCRATCHDIR will not be removed"
trap cleanup EXIT
fi
missing_versions() {
$PSQL -t <<-EOF
SELECT * FROM (VALUES ('$1'), ('$2')) AS foo
EXCEPT
SELECT version FROM pg_available_extension_versions
WHERE name = 'timescaledb' AND version IN ('$1', '$2');
EOF
}
set -e
echo "**** Scratch directory: ${SCRATCHDIR}"
echo "**** Update files in directory ${BASE_DIR}/test/sql/updates"
cd ${BASE_DIR}/test/sql/updates
$PSQL -c '\conninfo'
# shellcheck disable=SC2207 # Prefer mapfile or read -a to split command output (or quote to avoid splitting).
missing=($(missing_versions $UPDATE_FROM_TAG $UPDATE_TO_TAG))
if [[ ${#missing[@]} -gt 0 ]]; then
echo "ERROR: Missing version(s) ${missing[*]} of 'timescaledb'"
echo "Available versions: " "$($PSQL -tc "SELECT version FROM pg_available_extension_versions WHERE name = 'timescaledb'")"
exit 1
fi
# For the comments below, we assume the upgrade is from 1.7.5 to 2.0.2
# (this is just an example, the real value is given by variables
# above).
# Create a 1.7.5 version Upgrade
echo "---- Connecting to ${FORGE_CONNINFO} and running setup ----"
$PSQL -c "DROP EXTENSION IF EXISTS timescaledb CASCADE" >>$LOGFILE 2>&1
$PSQL -f pre.cleanup.sql >>$LOGFILE 2>&1
$PSQL -c "CREATE EXTENSION timescaledb VERSION '${UPDATE_FROM_TAG}'" >>$LOGFILE 2>&1
$PSQL -c "\dx"
# Run setup on Upgrade
$PSQL -f pre.smoke.sql >>$LOGFILE 2>&1
$PSQL -f setup.${TEST_VERSION}.sql >>$LOGFILE 2>&1
# Run update on Upgrade. You now have a 2.0.2 version in Upgrade.
$PSQL -c "ALTER EXTENSION timescaledb UPDATE TO '${UPDATE_TO_TAG}'" >>$LOGFILE 2>&1
echo -n "Dumping the contents of Upgrade..."
pg_dump -Fc -f $DUMPFILE >>$LOGFILE 2>&1
echo "done"
# Run the post scripts on Upgrade to get UpgradeOut to compare
# with. We can now discard Upgrade database.
echo -n "Collecting post-update status..."
$PSQL -f post.${TEST_VERSION}.sql >$UPGRADE_OUT
echo "done"
echo "---- Create a ${UPDATE_TO_TAG} version Clean ----"
$PSQL -c "DROP EXTENSION IF EXISTS timescaledb CASCADE" >>$LOGFILE 2>&1
$PSQL -f pre.cleanup.sql >>$LOGFILE 2>&1
$PSQL -c "CREATE EXTENSION timescaledb VERSION '${UPDATE_TO_TAG}'" >>$LOGFILE 2>&1
$PSQL -c "\dx"
echo "---- Run the setup scripts on Clean, with post-update actions ----"
$PSQL -f pre.smoke.sql >>$LOGFILE 2>&1
$PSQL -f setup.${TEST_VERSION}.sql >>$LOGFILE 2>&1
echo "---- Run the post scripts on Clean to get output CleanOut ----"
$PSQL -f post.${TEST_VERSION}.sql >$CLEAN_OUT
$PSQL -f cleanup.${TEST_VERSION}.sql >>$LOGFILE 2>&1
echo "---- Create a ${UPDATE_TO_TAG} version Restore ----"
$PSQL -c "DROP EXTENSION IF EXISTS timescaledb CASCADE" >>$LOGFILE 2>&1
$PSQL -f pre.cleanup.sql >>$LOGFILE 2>&1
$PSQL -c "CREATE EXTENSION timescaledb VERSION '${UPDATE_TO_TAG}'" >>$LOGFILE 2>&1
$PSQL -c "\dx"
echo "---- Restore the UpgradeDump into Restore ----"
echo -n "Restoring dump..."
$PSQL -c "SELECT timescaledb_pre_restore()" >>$LOGFILE 2>&1
pg_restore -d $PGDATABASE $DUMPFILE >>$LOGFILE 2>&1 || true
$PSQL -c "SELECT timescaledb_post_restore()" >>$LOGFILE 2>&1
echo "done"
echo "---- Run the post scripts on Restore to get a RestoreOut ----"
$PSQL -f post.${TEST_VERSION}.sql >$RESTORE_OUT
echo "---- Compare UpgradeOut with CleanOut and make sure they are identical ----"
diff -u $UPGRADE_OUT $CLEAN_OUT && echo "No difference between $UPGRADE_OUT and $CLEAN_OUT" | tee $SCRATCHDIR/upgrade-clean.diff
echo "---- Compare RestoreOut with CleanOut and make sure they are identical ----"
diff -u $RESTORE_OUT $CLEAN_OUT && echo "No difference between $RESTORE_OUT and $CLEAN_OUT" | tee $SCRATCHDIR/restore-clean.diff
$PSQL -f cleanup.${TEST_VERSION}.sql >>$LOGFILE 2>&1