#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2019-2021, Intel Corporation

#
# run-build.sh - is called inside a Docker container,
#                starts pmemkv builds (defined by the CI jobs) with tests.
#

set -e

source `dirname ${0}`/prepare-for-build.sh

# params set for the file (if not previously set, the right-hand param is used)
TEST_DIR=${PMEMKV_TEST_DIR:-${DEFAULT_TEST_DIR}}
BUILD_JSON_CONFIG=${BUILD_JSON_CONFIG:-ON}
CHECK_CPP_STYLE=${CHECK_CPP_STYLE:-ON}
TESTS_LONG=${TESTS_LONG:-OFF}
TESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM:-ON}
TESTS_ASAN=${TESTS_ASAN:-OFF}
TESTS_UBSAN=${TESTS_UBSAN:-OFF}
TEST_TIMEOUT=${TEST_TIMEOUT:-600}

###############################################################################
# BUILD tests_gcc_debug_cpp11
###############################################################################
function tests_gcc_debug_cpp11() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"
	mkdir build
	cd build

	CC=gcc CXX=g++ \
	cmake .. -DCMAKE_BUILD_TYPE=Debug \
		-DTEST_DIR=${TEST_DIR} \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DCOVERAGE=${COVERAGE} \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG} \
		-DCHECK_CPP_STYLE=${CHECK_CPP_STYLE} \
		-DTESTS_LONG=${TESTS_LONG} \
		-DDEVELOPER_MODE=1 \
		-DTESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM} \
		-DTESTS_PMEMOBJ_DRD_HELGRIND=1 \
		-DCXX_STANDARD=11 \
		-DUSE_ASAN=${TESTS_ASAN} \
		-DUSE_UBSAN=${TESTS_UBSAN}

	make -j$(nproc)
	ctest -E "_memcheck|_drd|_helgrind|_pmemcheck|_pmreorder" --timeout ${TEST_TIMEOUT} --output-on-failure

	if [ "${COVERAGE}" == "1" ]; then
		upload_codecov gcc_debug_cpp11
	fi

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

###############################################################################
# BUILD tests_gcc_debug_cpp14
###############################################################################
function tests_gcc_debug_cpp14() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"
	mkdir build
	cd build

	CC=gcc CXX=g++ \
	cmake .. -DCMAKE_BUILD_TYPE=Debug \
		-DTEST_DIR=${TEST_DIR} \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DCOVERAGE=${COVERAGE} \
		-DENGINE_CSMAP=1 \
		-DENGINE_RADIX=1 \
		-DENGINE_ROBINHOOD=1 \
		-DENGINE_DRAM_VCMAP=1 \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG} \
		-DTESTS_LONG=${TESTS_LONG} \
		-DDEVELOPER_MODE=1 \
		-DTESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM} \
		-DTESTS_PMEMOBJ_DRD_HELGRIND=1 \
		-DCXX_STANDARD=14 \
		-DUSE_ASAN=${TESTS_ASAN} \
		-DUSE_UBSAN=${TESTS_UBSAN}

	make -j$(nproc)
	ctest -E "_memcheck|_drd|_helgrind|_pmemcheck|_pmreorder" --timeout ${TEST_TIMEOUT} --output-on-failure

	if [ "${COVERAGE}" == "1" ]; then
		upload_codecov gcc_debug_cpp14
	fi

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

###############################################################################
# BUILD tests_gcc_debug_cpp14_valgrind_other
###############################################################################
function tests_gcc_debug_cpp14_valgrind_other() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"
	mkdir build
	cd build

	CC=gcc CXX=g++ \
	cmake .. -DCMAKE_BUILD_TYPE=Debug \
		-DTEST_DIR=${TEST_DIR} \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DCOVERAGE=${COVERAGE} \
		-DENGINE_CSMAP=1 \
		-DENGINE_RADIX=1 \
		-DENGINE_ROBINHOOD=1 \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG} \
		-DTESTS_LONG=${TESTS_LONG} \
		-DTESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM} \
		-DCXX_STANDARD=14

	make -j$(nproc)
	ctest -R "_helgrind|_pmemcheck|_pmreorder" --timeout ${TEST_TIMEOUT} --output-on-failure

	if [ "${COVERAGE}" == "1" ]; then
		upload_codecov gcc_debug_cpp14_valgrind_other
	fi

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

###############################################################################
# BUILD tests_gcc_debug_cpp14_valgrind_memcheck_drd
###############################################################################
function tests_gcc_debug_cpp14_valgrind_memcheck_drd() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"
	mkdir build
	cd build

	CC=gcc CXX=g++ \
	cmake .. -DCMAKE_BUILD_TYPE=Debug \
		-DTEST_DIR=${TEST_DIR} \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DCOVERAGE=${COVERAGE} \
		-DENGINE_CSMAP=1 \
		-DENGINE_RADIX=1 \
		-DENGINE_ROBINHOOD=1 \
		-DENGINE_DRAM_VCMAP=1 \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG} \
		-DTESTS_LONG=${TESTS_LONG} \
		-DTESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM} \
		-DTESTS_PMEMOBJ_DRD_HELGRIND=1 \
		-DCXX_STANDARD=14

	make -j$(nproc)
	ctest -R "_memcheck|_drd" --timeout ${TEST_TIMEOUT} --output-on-failure

	if [ "${COVERAGE}" == "1" ]; then
		upload_codecov gcc_debug_cpp14_valgrind_memcheck_drd
	fi

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

###############################################################################
# BUILD tests_clang_release_cpp20 llvm
###############################################################################
function tests_clang_release_cpp20() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"

	# CXX_STANDARD==20 is supported since CMake 3.12
	if [ ${CMAKE_VERSION_NUMBER} -lt 312 ]; then
		echo "ERROR: C++20 is supported in CMake since 3.12, installed version: ${CMAKE_VERSION}"
		exit 1
	fi

	mkdir build
	cd build

	CC=clang CXX=clang++ cmake .. -DCMAKE_BUILD_TYPE=Release \
		-DTEST_DIR=${TEST_DIR} \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DCOVERAGE=${COVERAGE} \
		-DENGINE_RADIX=1 \
		-DENGINE_ROBINHOOD=1 \
		-DENGINE_DRAM_VCMAP=1 \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG} \
		-DTESTS_LONG=${TESTS_LONG} \
		-DTESTS_USE_FORCED_PMEM=${TESTS_USE_FORCED_PMEM} \
		-DTESTS_PMEMOBJ_DRD_HELGRIND=1 \
		-DDEVELOPER_MODE=1 \
		-DCXX_STANDARD=20 \
		-DUSE_ASAN=${TESTS_ASAN} \
		-DUSE_UBSAN=${TESTS_UBSAN}

	make -j$(nproc)
	ctest -E "_memcheck|_drd|_helgrind|_pmemcheck|_pmreorder" --timeout ${TEST_TIMEOUT} --output-on-failure

	if [ "${COVERAGE}" == "1" ]; then
		upload_codecov clang_release_cpp20
	fi

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

###############################################################################
# BUILD test_release_installation
###############################################################################
function test_release_installation() {
	printf "\n$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} START$(tput sgr 0)\n"
	mkdir build
	cd build

	CC=gcc CXX=g++ \
	cmake .. -DCMAKE_BUILD_TYPE=Release \
		-DENGINE_RADIX=1 \
		-DBUILD_TESTS=0 \
		-DCMAKE_INSTALL_PREFIX=${PREFIX} \
		-DBUILD_JSON_CONFIG=${BUILD_JSON_CONFIG}

	make -j$(nproc)
	sudo_password -S make -j$(nproc) install

	echo "Verify installed libraries:"
	compile_example_standalone pmemkv_basic_cpp
	run_example_standalone pmemkv_basic_cpp pool

	# Execute examples with special requirements and some unregular use cases
	echo "Poolset example:"
	compile_example_standalone pmemkv_open_cpp
	pmempool create -l "pmemkv" obj ${WORKDIR}/examples/example.poolset
	run_example_standalone pmemkv_open_cpp ${WORKDIR}/examples/example.poolset

	echo "Expect failure - non-existing path is passed:"
	run_example_standalone pmemkv_open_cpp /non-existing/path && exit 1

	if [ "${BUILD_JSON_CONFIG}" == "ON" ]; then
		echo "Config example (require JSON helper library):"
		compile_example_standalone pmemkv_config_c
		run_example_standalone pmemkv_config_c
		run_example_standalone pmemkv_basic_config_c pool
	fi

	echo "Filling up database (C++) example:"
	compile_example_standalone pmemkv_fill_cpp
	run_example_standalone pmemkv_fill_cpp pool 10485760 cmap 8 8

	echo "Transaction C++ example:"
	compile_example_standalone pmemkv_transaction_cpp
	pmempool create -l "pmemkv_radix" obj ${WORKDIR}/examples/example.poolset
	run_example_standalone pmemkv_transaction_cpp ${WORKDIR}/examples/example.poolset

	echo "Transaction C example:"
	compile_example_standalone pmemkv_transaction_c
	pmempool rm -f ${WORKDIR}/examples/example.poolset
	pmempool create -l "pmemkv_radix" obj ${WORKDIR}/examples/example.poolset
	run_example_standalone pmemkv_transaction_c ${WORKDIR}/examples/example.poolset

	echo "Uninstall libraries"
	cd ${WORKDIR}/build
	sudo_password -S make uninstall

	workspace_cleanup
	printf "$(tput setaf 1)$(tput setab 7)BUILD ${FUNCNAME[0]} END$(tput sgr 0)\n\n"
}

# Main:
cd ${WORKDIR}

echo "### Cleaning workspace"
workspace_cleanup

echo
echo "### Making sure there is no libpmemkv currently installed"
echo "---------------------------- Error expected! ------------------------------"
compile_example_standalone pmemkv_basic_cpp && exit 1
echo "---------------------------------------------------------------------------"

echo "Run build steps passed as script arguments:"
build_steps=$@
echo "Defined build steps: ${build_steps}"

if [[ -z "${build_steps}" ]]; then
	echo "ERROR: The variable build_steps with selected builds to run is not set!"
	exit 1
fi

for build in ${build_steps}
do
	${build}
done
