#!/bin/bash

route_prefix=medical_check

err_report() {
    echo "$0: Error on line $1 - aborted"
    exit 1
}

trap 'err_report $LINENO' ERR

# Any failure causes exit
set -e
export DISABLE_SPRING=1

cleanup_db()
{
    echo Dropping database ...
    $rake db:drop
    echo Removing migrations ...
    rm -f db/migrate/* db/schema.rb
    case `ruby -e 'puts JRUBY_VERSION' 2> /dev/null` in
	[0-9]*)
        echo 'Jruby requires the database to be created before the server is started: running rake db:migrate'
        $rake db:migrate
	;;
    esac
}

case "$1" in
redo)
    . test/init_variables
    cd $railsapp
    cleanup_db
    actual_rails_version=`$rails -v`
    ;;
*)
    . test/setup_railsapp $1
    ;;
esac

run_test=$2

cd $railsapp
date > $custom_file
rm -f $catchall_file

case `egrep '^[^#]*MiddlewareHealthcheck' config/application.rb` in
'')
  export has_middleware=false
  ;;
?*)
  export has_middleware=true
  ;;
esac


testurl="$base_dir/test/testurl"
fake_smtp_server="$base_dir/test/fake_smtp_server"

server_pid=''
fake_smtp_pid=''

pick_a_port()
{
    while :
    do
        port=`expr 10000 + $RANDOM`
        # Check Tcp ports in Listen mode with No address resolution
        if (netstat -tln | egrep ":${port} .*:"); then
            echo "(Skipping used port)"
        else
            break
        fi
    done
}


start_server()
{
    # restart migration list
    rm -rf db/migrate db/schema.rb
    mkdir -p db/migrate

    # Increment port each time to make sure we have not trouble with address/port already allocated
    pick_a_port
    host=http://127.0.0.1:${port}
    bundle_prefix=''
    if [ -f Gemfile ]
    then
        bundle_prefix='bundle exec'
    fi
    server_arg=${RAILS_SERVER:-webrick}
    echo "start_server called using: `env | egrep '^RAILS|^RACK|^PATH='` $bundle_prefix $server_arg"
    case "$server_arg" in
    puma) 
        $bundle_prefix puma -b tcp://127.0.0.1:$port &
        ;;
    passenger) 
        $bundle_prefix passenger start -p $port &
        ;;
    thin) 
        $bundle_prefix thin start -p $port &
        ;;
    unicorn) 
        $bundle_prefix unicorn_rails -l 127.0.0.1:$port &
        ;;
    *)
        if [ -x script/server ]
        then
            echo Starting server on port $port using $bundle_prefix ./script/server ...
            $bundle_prefix ./script/server $server_arg -p $port &
        else
            echo Starting server on port $port using $rails s ...
            $bundle_prefix $rails server $server_arg -p $port &
        fi
        ;;
    esac
    server_pid=$!
    echo Server pid: $server_pid
    sleep 3
    echo
    echo 'Checking server is up ...'
    for i in 1 2 3 4 5 6
    do
      if $testurl ${host}/static.txt ; then
        break
      fi
      if kill -0 $server_pid ; then
        echo "waiting ${i} ..."
      else
        echo "ERROR: Server has died!!"
        exit 3
      fi
   done
}

stop_server()
{
    case "$server_pid" in
        [0-9]*)
            echo ========================================================
            echo "Killing rails server [pid: $server_pid]"
            kill -QUIT $server_pid  || echo server has already exited ..
            if [ -x bin/spring ] ; then
                echo Stopping spring ...
                bin/spring stop || echo spring had already exited ..
            fi
            sleep 1
            kill -9 $server_pid  || echo server had already exited ...
            sleep 1
            # needed for unicorn - it doesn't die when it is supposed to
            killall "$server_arg" || echo server and child processes had already stopped ...
            ;;
    esac
    case "$fake_smtp_pid" in
        [0-9]*)
            echo ========================================================
            echo "Killing fake smtp server [pid: $fake_smtp_pid]"
            kill -QUIT $fake_smtp_pid || echo fake_smtp had already exited ..
            sleep 2
            kill -9 $fake_smtp_pid || echo fake_smtp had already exited ..
            ;;
    esac
    server_pid=''
    fake_smtp_pid=''
    ps -f
    echo Waiting for sub processes to complete ...
    wait
    echo Finished waiting for sub processes, sleeping 2 seconds ...
    sleep 2
}

finish()
{
    set +e
    echo ========================================================
    echo TEST ${1:-FAILED}
    echo ========================================================
    echo Result of: ls -lR $railsapp/log $railsapp/db
    ls -lR $railsapp/log $railsapp/db

    if [ -s $railsapp/log/test.log ]
    then
        echo ========================================================
        echo Last 50 lines of test log
        tail -50 $railsapp/log/test.log
    fi

    if [ -s $railsapp/log/production.log ]
    then
        echo ========================================================
        echo Last 50 lines of production log
        tail -50 $railsapp/log/production.log
    fi

    stop_server
    trap "" 0
    echo ========================================================
    ps uxf || echo ps failed
    echo ========================================================
    echo TEST ${1:-FAILED}, exiting with status ${2:-2}
    echo ========================================================
    exit ${2:-2}
}

trap "finish FAILED 1" 0

common_tests()
{

    test_no=$1

    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: CHECKING routes exist..."
        $rake routes | tee /tmp/t$$
        echo
        case `egrep ${route_prefix} /tmp/t$$ || true` in
        '')
          echo WARNING - routes for ${route_prefix} not listed!
          ;;
        esac
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING can get a static file ..."
        case "$RAILS_ENV=`egrep '^\s*config.serve_static_[asetfil]* *= *false' config/environments/${RAILS_ENV}.rb`" in
        production*static*false*)
            echo "  SKIPPED (disabled in production)"
            ;;
        *)
            grep serve_static_files config/environments/${RAILS_ENV}.rb config/[a-z]*.rb || echo no serve_static_files entry
            $testurl ${host}/static.txt 200 text/plain STATIC-FILE
            ;;
        esac
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING can get an example controller ..."
        $testurl ${host}/example 200 text/plain 'example page'
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING direct call to catchall method on example controller ..."
        $testurl ${host}/example/catchall 200 text/plain 'catch all route'
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should pass with no database migrations ..."
        ls db/migrate
        $testurl ${host}/${route_prefix}/migration 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should fail without initial database migration ..."
        cp $base_dir/test/migrate/nine/* db/migrate
        ls db/migrate
        $testurl ${host}/${route_prefix}/migration 550 text/plain failed
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/database should pass without initial database migration (since it ignores the difference) ..."
        $testurl ${host}/${route_prefix}/database 200 text/plain $success
        echo
    fi



    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/site should pass ..."
        $testurl ${host}/${route_prefix}/site 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should pass after initial database migration ..."
        $rake db:migrate
        $testurl ${host}/${route_prefix}/migration 200 text/plain $success
        echo
    fi

    #test with coruppted DB
    rm -rf db.bak
    cp -R db db.bak
    for f in db/*.sqlite3
    do
        echo CORRUPTED > $f
    done

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/database should fail if the database has been corrupted ..."

        $testurl ${host}/${route_prefix}/database 550 text/plain failed
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/site should pass ..."
        $testurl ${host}/${route_prefix}/site 200 text/plain $success
        if $has_middleware; then
            echo "${test_no}: TESTING ${route_prefix}/middleware_site should pass ..."
            $testurl ${host}/${route_prefix}/middleware_site 200 text/plain $success
        fi
        echo
    fi

    # Restore database
    cp -f db.bak/*.sqlite3 db/

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should fail without all migrations ..."
        cp $base_dir/test/migrate/twelve/* db/migrate

        ls db/migrate
        $testurl ${host}/${route_prefix}/migration 550 text/plain failed
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should pass after both database migrations ..."
        $rake db:migrate
        $testurl ${host}/${route_prefix}/migration 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/migration should pass after both database migrations ..."
        $rake db:migrate
        $testurl ${host}/${route_prefix}/migration 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/email should fail without smtp available ..."
        $testurl ${host}/${route_prefix}/email 550 text/plain failed
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/email should pass with smtp available ..."
        $fake_smtp_server &
        fake_smtp_pid=$!
        sleep 5
        $testurl ${host}/${route_prefix}/email 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix} (all) should fail without smtp available ..."
        $testurl ${host}/${route_prefix} 550 text/plain failed
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/all should fail without smtp available ..."
        $testurl ${host}/${route_prefix} 550 text/plain failed
        echo
    fi

    kill -9 $fake_smtp_pid || echo fake_smtp_server had finished as expected
    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix} (all) should pass with smtp available ..."
        $fake_smtp_server &
        fake_smtp_pid=$!
        sleep 5
        $testurl ${host}/${route_prefix} 200 text/plain $success
        echo
    fi

    kill -9 $fake_smtp_pid || echo fake_smtp_server had finished as expected
    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/all should pass with smtp available ..."
        $fake_smtp_server &
        fake_smtp_pid=$!
        sleep 5
        $testurl ${host}/${route_prefix}/all 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/pass should pass ..."
        $testurl ${host}/${route_prefix}/pass 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/custom should pass ..."
        $testurl ${host}/${route_prefix}/custom 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/custom.html should pass (returning plain text) ..."
        $testurl ${host}/${route_prefix}/custom.html 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/custom.json should pass ..."
        $testurl ${host}/${route_prefix}/custom.json 200 application/json '"healthy":true'
        $testurl ${host}/${route_prefix}/custom.json 200 application/json "\"message\":\"$success\""
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/custom.xml should pass ..."
        $testurl ${host}/${route_prefix}/custom.xml 200 application/xml '<healthy type="boolean">true</healthy>'
        $testurl ${host}/${route_prefix}/custom.xml 200 application/xml "<message>$success</message>"
        echo
    fi

    test_no=`expr 1 + $test_no`
    rm -f $custom_file
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/custom should fail when custom returns string ..."
        $testurl ${host}/${route_prefix}/custom 550 text/plain failed
        echo
    fi

    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}/pass should pass even if other custom test returns string ..."
        $testurl ${host}/${route_prefix}/pass 200 text/plain $success
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix} (all) should fail when custom check fails ..."
        $testurl ${host}/${route_prefix} 550 text/plain "$custom_file is missing!"
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}.json (all) should fail when custom check fails ..."
        $testurl ${host}/${route_prefix}.json 555 application/json '"healthy":false'
        $testurl ${host}/${route_prefix}.json 555 application/json "$custom_file is missing!"
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING ${route_prefix}.xml (all) should fail when custom check fails ..."
        $testurl ${host}/${route_prefix}.xml 555 application/xml '<healthy type="boolean">false</healthy>'
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        if $has_middleware; then
            echo "${test_no}: TESTING ${route_prefix}/middleware_site should pass ..."
            $testurl ${host}/${route_prefix}/middleware_site 200 text/plain $success
        else
            echo "${test_no}: TESTING ${route_prefix}/middleware_site should fail ..."
            $testurl ${host}/${route_prefix}/middleware_site 550 text/plain failed
        fi
        echo
    fi

    test_no=`expr 1 + $test_no`
    if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then
        echo "${test_no}: TESTING log files to check for deprecation warnings ..."
        if egrep ' is deprecated|DEPRECATION WARNING' $railsapp/log/[tp][er][so][td]*.log 
        then
            echo Found deprecation warnings - failed test
            exit 99
        fi
    fi

    date > $custom_file
}

# required for rails 4.1+ in production mode
export SECRET_KEY_BASE=cf2f49c38a3fe67416ddf680f4f3187c0fce7dd1b9b117b34d195df75b274e08a04877e23803b2fdf1aa9a655269d94bc4888aa325cf7e721cc47368cfe56a80

# required for rails 5 to server static files
export RAILS_SERVE_STATIC_FILES=on

export IP_WHITELIST='123.123.123.123'
unset AUTH_USER
unset AUTH_PASSWORD

case "$run_test" in
''|[12])
    echo ========================================================
    echo TESTING whitelist ban WITHOUT CATCHALL in test env
    echo ========================================================
    export RAILS_ENV=test RACK_ENV=test

    start_server

    echo '1: TESTING controller prohibited by ip...'
    expected_status=403
    $testurl ${host}/${route_prefix}/site $expected_status

    if $has_middleware; then
        echo
        echo '2: TESTING middleware prohibited by ip...'
        expected_status=403
        $testurl ${host}/${route_prefix}/middleware $expected_status
    fi
    ;;
esac

export IP_WHITELIST=''
export AUTH_USER='someone'
export AUTH_PASSWORD='secret'

case "$run_test" in
''|[3456789]|10)
    echo ========================================================
    echo TESTING basic auth, no whitelist WITHOUT CATCHALL in test env
    echo ========================================================
    export RAILS_ENV=test RACK_ENV=test

    case "$run_trest" in
     '')
        stop_server
        cleanup_db
        ;;
    esac

    start_server

    expected_status=401
    echo '3: TESTING controller without authentication insists on authentication ...'
    AUTH_USER= $testurl ${host}/${route_prefix}/site $expected_status

    echo '4: TESTING controller with wrong password insists on authentication ...'
    AUTH_PASSWORD=wrong $testurl ${host}/${route_prefix}/site $expected_status

    echo '5: TESTING controller with wrong user insists on authentication ...'
    AUTH_USER=wrong $testurl ${host}/${route_prefix}/site $expected_status

    echo '6: TESTING controller with authentication works ...'
    expected_status=200
    $testurl ${host}/${route_prefix}/site $expected_status

    if $has_middleware; then
        echo
        echo '7: TESTING middleware without authentication insists on authentication ...'
        expected_status=401
        AUTH_USER= $testurl ${host}/${route_prefix}/middleware $expected_status

        echo
        echo '8: TESTING middleware with wrong password insists on authentication ...'
        AUTH_PASSWORD=wrong $testurl ${host}/${route_prefix}/middleware $expected_status

        echo
        echo '9: TESTING middleware with wrong user insists on authentication ...'
        AUTH_USER=wrong $testurl ${host}/${route_prefix}/middleware $expected_status

        echo
        echo '10: TESTING middleware with authentication works ...'
        expected_status=200
        $testurl ${host}/${route_prefix}/middleware $expected_status
    else
        echo
        echo "Skipped middleware tests as it is not configured..."
    fi
    ;;
esac

unset AUTH_USER
unset AUTH_PASSWORD

case "$run_test" in
''|1??)
    echo ========================================================
    echo TESTING WITHOUT CATCHALL, no whitelist or user in test env
    echo ========================================================
    export RAILS_ENV=test RACK_ENV=test

    case "$run_trest" in
     '')
        stop_server
        cleanup_db
        ;;
    esac

    start_server

    # get a static file

    echo
    echo 'TESTING no catchall route active ...'
    expected_status=404,500,502
    $testurl ${host}/another/url $expected_status

    echo 'TESTING default route has been overriden ...'
    expected_status=404,500,502
    $testurl ${host}/health_check/site $expected_status

    common_tests 100
    ;;
esac

export IP_WHITELIST='127.0.0.1'
export AUTH_USER='someone'
export AUTH_PASSWORD='secret'

case "$run_test" in
''|2??)
    echo ========================================================
    echo TESTING WITH CATCHALL with whitelist and user in ${RAILS_ENV2:-production} env
    echo ========================================================
    export RAILS_ENV=${RAILS_ENV2:-production} RACK_ENV=${RAILS_ENV2:-production}

    case "$run_trest" in
     '')
        stop_server
        cleanup_db
        ;;
    esac

    date > $catchall_file

    start_server

    echo
    echo 'TESTING catchall route active ...'
    $testurl ${host}/another/url 200 text/plain 'catch all route'
    echo

    common_tests 200
    ;;
esac

rm -f $catchall_file

finish PASSED 0
exit 0

# vi: sw=4 ai sm:
