#!/bin/sh

# Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# Include common test library.
. @abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh

# Include admin utilities
. @abs_top_srcdir@/src/bin/admin/admin-utils.sh

# Set path to the production schema scripts
db_scripts_dir=@abs_top_srcdir@/src/share/database/scripts

db_user="keatest"
db_password="keatest"
db_name="keatest"
db_host="localhost"

# Set location of the kea-admin.
keaadmin=@abs_top_builddir@/src/bin/admin/kea-admin

# Convenience function for running an SQL statement
# param hdr - text message to prepend to any error
# param qry - SQL statement to run
# param exp_valu - optional expected value.  This can be used IF the SQL statement
# generates a single value, such as a SELECT which returns one column for one row.
# Examples:
#
#   qry="insert into lease6 (address, lease_type, subnet_id, state) values ($addr,$ltype,1,0);"
#   run_statement "#2" "$qry"
#
#   qry="select leases from lease6_stat where subnet_id = 1 and lease_type = $ltype and state = 0";
#   run_statement "#3" "$qry" 1
run_statement() {
    hdr="$1";shift;
    qry="$1";shift;
    exp_value="$1";

    # Execute the statment
    value=`pgsql_execute "${qry}"`
    ERRCODE=$?

    # Execution should succeed
    assert_eq 0 $ERRCODE "$hdr: SQL=[$qry] failed: (expected status code %d, returned %d)"

    # If there's an expected value, test it
    if [ "x$exp_value" != "x" ]
    then
        assert_str_eq "$exp_value" "$value" "$hdr: SQL=[$qry] wrong: (expected value %s, returned %s)"
    fi
}

# Wipe all tables from the DB:
pgsql_wipe() {
    printf "Wiping whole database %s\n" $db_name
    export PGPASSWORD=$db_password

    cat $db_scripts_dir/pgsql/dhcpdb_drop.pgsql | psql --set ON_ERROR_STOP=1 -A -t -h localhost -q -U keatest -d keatest >/dev/null 2>&1
    assert_eq 0 $?  "pgsql_wipe drop failed, expected exit code: %d, actual: %d"
}

pgsql_lease_init_test() {
    test_start "pgsql.lease-init"

    # Let's wipe the whole database
    pgsql_wipe

    # Create the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    assert_eq 0 $? "kea-admin lease-init pgsql failed, expected exit code: %d, actual: %d"

    # Verify that all the expected tables exist

    # Check schema_version table
    RESULT=`pgsql_execute "SELECT version, minor FROM schema_version;"`
    assert_eq 0 $? "schema_version table check failed, expected exit code: %d, actual: %d"

    # Check lease4 table
    RESULT=`pgsql_execute "SELECT address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease4;"`
    assert_eq 0 $? "lease4 table check failed, expected exit code: %d, actual: %d"

    # Check lease6 table
    RESULT=`pgsql_execute "SELECT address, duid, valid_lifetime, expire, subnet_id, pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease6;"`
    assert_eq 0 $? "lease6 table check failed, expected exit code: %d, actual: %d"

    # Check lease6_types table
    RESULT=`pgsql_execute "SELECT lease_type, name FROM lease6_types;"`
    assert_eq 0 $? "lease6_types table check failed, expected exit code: %d, actual: %d"

    # Check lease_state table
    RESULT=`pgsql_execute "SELECT state, name FROM lease_state;"`
    assert_eq 0 $? "lease_state table check failed, expected exit code: %d, actual: %d"

    # Trying to create it again should fail.  This verifies the db present
    # check
    echo ""
    echo "DB created successfully, make sure we aren't allowed to try it again:"
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    assert_eq 2 $? "kea-admin failed to deny lease-init, expected exit code: %d, actual: %d"

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

pgsql_lease_version_test() {
    test_start "pgsql.lease-version"

    # Wipe the whole database
    pgsql_wipe

    # Create the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    assert_eq 0 $? "cannot initialize the database, expected exit code: %d, actual: %d"

    # Verify that kea-admin lease-version returns the correct version
    version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name)
    assert_str_eq "5.0" ${version} "Expected kea-admin to return %s, returned value was %s"

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

pgsql_upgrade_1_0_to_2_0() {
    # Added state column to lease4
    output=`pgsql_execute "select state from lease4;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease4 is missing state column. (expected status code %d, returned %d)"

    # Added state column to lease6
    output=`pgsql_execute "select state from lease6;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease6 is missing state column. (expected status code %d, returned %d)"

    # Added stored procedures for lease dumps
    output=`pgsql_execute "select lease4DumpHeader from lease4DumpHeader();"`
    assert_eq 0 $ERRCODE "function lease4DumpHeader() broken or missing. (expected status code %d, returned %d)"

    output=`pgsql_execute "select address from lease4DumpData();"`
    assert_eq 0 $ERRCODE "function lease4DumpData() broken or missing. (expected status code %d, returned %d)"

    output=`pgsql_execute "select lease6DumpHeader from lease6DumpHeader();"`
    assert_eq 0 $ERRCODE "function lease6DumpHeader() broken or missing. (expected status code %d, returned %d)"

    output=`pgsql_execute "select address from lease6DumpData();"`
    assert_eq 0 $ERRCODE "function lease6DumpData() broken or missing. (expected status code %d, returned %d)"
}

pgsql_upgrade_2_0_to_3_0() {
    # Added hwaddr, hwtype, and hwaddr_source columns to lease6 table
    output=`pgsql_execute "select hwaddr, hwtype, hwaddr_source from lease6;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease6 table not upgraded to 3.0 (expected status code %d, returned %d)"

    # Added lease_hwaddr_source table
    output=`pgsql_execute "select hwaddr_source, name from lease_hwaddr_source;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease_hwaddr_source table is missing or broken. (expected status code %d, returned %d)"

    # Added hosts table
    output=`pgsql_execute "select host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes, dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key from hosts;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "hosts table is missing or broken. (expected status code %d, returned %d)"

    # Added ipv6_reservations table
    output=`pgsql_execute "select reservation_id, address, prefix_len, type, dhcp6_iaid, host_id from ipv6_reservations;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "ipv6_reservations table is missing or broken. (expected status code %d, returned %d)"

    # Added dhcp4_options table
    output=`pgsql_execute "select option_id, code, value, formatted_value, space, persistent, dhcp_client_class, dhcp4_subnet_id, host_id, scope_id from dhcp4_options;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dhcp4_options table is missing or broken. (expected status code %d, returned %d)"

    # Added dhcp6_options table
    output=`pgsql_execute "select option_id, code, value, formatted_value, space, persistent, dhcp_client_class, dhcp6_subnet_id, host_id,scope_id from dhcp6_options;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dhcp6_options table is missing or broken. (expected status code %d, returned %d)"

    # Added  host_identifier_type table
    output=`pgsql_execute "select type, name from host_identifier_type;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "host_identifier_type table is missing or broken. (expected status code %d, returned %d)"

    # Added dhcp_option_scope table
    output=`pgsql_execute "select scope_id, scope_name from dhcp_option_scope;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dhcp_option_scope table is missing or broken. (expected status code %d, returned %d)"

    # Added dhcp6_options table
    output=`pgsql_execute "select option_id, code, value, formatted_value, space, persistent, dhcp_client_class, dhcp6_subnet_id, host_id,scope_id from dhcp6_options;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dhcp6_options table is missing or broken. (expected status code %d, returned %d)"

    # Added order by clause to lease4DumpData
    output=`pgsql_execute "select address from lease4DumpData();"`
    assert_eq 0 $ERRCODE "function lease4DumpData() broken or missing. (expected status code %d, returned %d)"
    output=`pgsql_execute "\sf lease4DumpData"`
    assert_eq 0 $ERRCODE "\sf of lease4DumpData failed. (expected status code %d, returned %d)"
    count=`echo $output | grep -ic "order by l\.address"`
    assert_eq 1 $count "lease4DumpData is missing order by clause"

    # Added hwaddr columns to lease6DumpHeader
    output=`pgsql_execute "select lease6DumpHeader from lease6DumpHeader();"`
    assert_eq 0 $ERRCODE "function lease6DumpHeader() broken or missing. (expected status code %d, returned %d)"
    count=`echo $output | grep -ic "hwaddr,hwtype,hwaddr_source"`
    assert_eq 1 $count "lease6DumpHeader is missing hwaddr columns"

    # Added hwaddr columns to lease6DumpData
    output=`pgsql_execute "select hwaddr,hwtype,hwaddr_source from lease6DumpData();"`
    assert_eq 0 $ERRCODE "function lease6DumpData() broken or missing. (expected status code %d, returned %d)"

    # Added order by clause to lease6DumpData
    output=`pgsql_execute "\sf lease4DumpData"`
    assert_eq 0 $ERRCODE "\sf of lease4DumpData failed. (expected status code %d, returned %d)"
    count=`echo $output | grep -ic "order by l\.address"`
    assert_eq 1 $count "lease4DumpData is missing order by clause"

    # lease_hardware_source should have row for source = 0
    output=`pgsql_execute "select count(hwaddr_source) from lease_hwaddr_source where hwaddr_source = 0 and name='HWADDR_SOURCE_UNKNOWN';"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "select from lease_hwaddr_source failed. (expected status code %d, returned %d)"
    assert_eq 1 "$output" "lease_hwaddr_source does not contain entry for HWADDR_SOURCE_UNKNOWN. (record count %d, expected %d)"
}

pgsql_upgrade_3_0_to_5_0() {
    # Verify upgraded schema reports version 5.0.
    version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
    assert_str_eq "5.0" ${version} "Expected kea-admin to return %s, returned value was %s"

    # Added user_context to lease4
    output=`pgsql_execute "select user_context from lease4;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease4 is missing user_context column. (expected status code %d, returned %d)"

    # Added user_context to lease6
    output=`pgsql_execute "select user_context from lease6;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "lease6 is missing user_context column. (expected status code %d, returned %d)"

    # Added logs table
    output=`pgsql_execute "select timestamp, address, log from logs;"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "logs table is missing or broken. (expected status code %d, returned %d)"
}

pgsql_upgrade_test() {
    test_start "pgsql.upgrade-test"

    # Wipe the whole database
    pgsql_wipe

    # Initialize database to schema 1.0.
    pgsql_execute_script @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.pgsql
    assert_eq 0 $? "cannot initialize the database, expected exit code: %d, actual: %d"

    ${keaadmin} lease-upgrade pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    assert_eq 0 $? "lease-upgrade failed, expected exit code: %d, actual: %d"

    # Check 1.0 to 2.0 upgrade
    pgsql_upgrade_1_0_to_2_0

    # Check 2.0 to 3.0 upgrade
    pgsql_upgrade_2_0_to_3_0

    # Check 3.0 to 5.0 upgrade
    pgsql_upgrade_3_0_to_5_0

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

# Given a valid timestamp string, returns a timestamp with timezone string
# for the give time localized by the PostgreSQL server.
get_local_time() {
    timestamp="$1"

    # Expiration field is a "timestamp with timezone" so we need a reference
    # time for the machine/DB this test is running upon.
    ref_timestamp=`pgsql_execute "select timestamptz '$1';"`
    ERRCODE=$?
    assert_eq 0 $ERRCODE "reference time query failed for [$timestamp], expected exit code %d, actual %d"
    echo $ref_timestamp
}


# Test verifies the ability to dump lease4 data to CSV file
# The dump output file is compared against a reference file.
# If the dump is successful, the file contents will be the
# same.  Note that the expire field in the lease4 table
# is of data type "timestamp with timezone". This means that
# the dumped file content is dependent upon the timezone
# setting the PostgreSQL server is using.  To account for
# this the reference data contains a tag, "<timestamp>"
# where the expire column's data would normally be. This
# tag is replaced during text execution with a value
# determined by querying the PostgreSQL server.  This
# updated reference data is captured in a temporary file
# which is used for the actual comparison.
pgsql_lease4_dump_test() {
    test_start "pgsql.lease4_dump_test"

    test_dir="@abs_top_srcdir@/src/bin/admin/tests"
    output_dir="@abs_top_builddir@/src/bin/admin/tests"
    script_dir="@abs_top_srcdir@/src/bin/admin/scripts"

    output_file="$output_dir/data/pgsql.lease4_dump_test.output.csv"

    ref_file="$test_dir/data/pgsql.lease4_dump_test.reference.csv"
    ref_file_tmp="$output_dir/data/pgsql.lease4_dump_test.reference.csv.tmp"

    # wipe out any residuals from prior failed runs
    if [ -e $output_file ]
    then
        rm $output_file
    fi

    if [ -e $ref_file_tmp ]
    then
        rm $ref_file_tmp
    fi

    # Let's wipe the whole database
    pgsql_wipe

    # Ok, now let's initialize the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?
    assert_eq 0 $ERRCODE "could not create database, expected exit code %d, actual %d"

    timestamp1="2015-01-01 01:15:30"
    timestamp2="2015-02-02 02:30:45"
    timestamp3="2015-03-03 11:01:07"

    # Insert the reference records
    insert_sql="\
insert into lease4 values(10,E'\\x20',E'\\x30',40,'$timestamp1',50,'t','t','one.example.com', 0, '');\
insert into lease4 values(11,'',E'\\x0123',40,'$timestamp2',50,'t','t','', 1, '');\
insert into lease4 values(12,E'\\x22','',40,'$timestamp3',50,'t','t','three.example.com', 2, '');"

    pgsql_execute "$insert_sql"
    ERRCODE=$?
    assert_eq 0 $ERRCODE "insert into lease4 failed, expected exit code %d, actual %d"

    # Dump lease4 to output_file
    ${keaadmin} lease-dump pgsql -4 -u $db_user -p $db_password -n $db_name -d $db_scripts_dir -o $output_file
    ERRCODE=$?
    assert_eq 0 $ERRCODE "kea-admin lease-dump -4 failed,  status code %d"

    # Expiration field is a "timestamp with timezone" so we need a localized reference
    # times for the machine/DB this test is running upon.
    local_timestamp1=`get_local_time "$timestamp1"`
    local_timestamp2=`get_local_time "$timestamp2"`
    local_timestamp3=`get_local_time "$timestamp3"`

    # Create the comparison file by replacing the <timestamp> tags
    # with the local reference timestamp
    sedstr="\
sed 's/<timestamp1>/$local_timestamp1/g' $ref_file | \
sed 's/<timestamp2>/$local_timestamp2/g' | \
sed 's/<timestamp3>/$local_timestamp3/g' "

    eval $sedstr >$ref_file_tmp
    ERRCODE=$?
    assert_eq 0 $ERRCODE "timestamp replacement failed, expected exit code %d, actual %d"

    # Compare the dump output to reference file, they should be identical
    cmp -s $output_file  $ref_file_tmp
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dump file does not match reference file, expected exit code %d, actual %d"

    # Remove the output file and temporary reference file
    rm $output_file
    rm $ref_file_tmp

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

# Test verifies the ability to dump lease6 data to CSV file
# The dump output file is compared against a reference file.
# If the dump is successful, the file contents will be the
# same.  Note that the expire field in the lease6 table
# is of data type "timestamp with timezone". This means that
# the dumped file content is dependent upon the timezone
# setting the PostgreSQL server is using.  To account for
# this the reference data contains a tag, "<timestamp>"
# where the expire column's data would normally be. This
# tag is replaced during text execution with a value
# determined by querying the PostgreSQL server.  This
# updated reference data is captured in a temporary file
# which is used for the actual comparison.
pgsql_lease6_dump_test() {
    test_start "pgsql.lease6_dump_test"

    test_dir="@abs_top_srcdir@/src/bin/admin/tests"
    output_dir="@abs_top_builddir@/src/bin/admin/tests"
    script_dir="@abs_top_srcdir@/src/bin/admin/scripts"

    output_file="$output_dir/data/pgsql.lease6_dump_test.output.csv"

    ref_file="$test_dir/data/pgsql.lease6_dump_test.reference.csv"
    ref_file_tmp="$output_dir/data/pgsql.lease6_dump_test.reference.csv.tmp"

    # wipe out any residuals from prior failed runs
    if [ -e $output_file ]
    then
        rm $output_file
    fi

    if [ -e $ref_file_tmp ]
    then
        rm $ref_file_tmp
    fi

    # Let's wipe the whole database
    pgsql_wipe

    # Ok, now let's initialize the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?
    assert_eq 0 $ERRCODE "could not create database,  status code %d"

    timestamp1="2015-04-04 01:15:30"
    timestamp2="2015-02-02 02:30:45"
    timestamp3="2015-06-06 11:01:07"

    # Insert the reference records
    insert_sql="\
insert into lease6 values(10,E'\\x20',30,'$timestamp1',40,50,1,60,70,'t','t','one.example.com', 0,decode('80','hex'),90,16,'');\
insert into lease6 values(11,'',30,'$timestamp2',40,50,1,60,70,'t','t','', 1,decode('80','hex'),90,1,'');\
insert into lease6 values(12,E'\\x21',30,'$timestamp3',40,50,1,60,70,'t','t','three.example.com', 2,decode('80','hex'),90,4,'');"

    pgsql_execute "$insert_sql"
    ERRCODE=$?
    assert_eq 0 $ERRCODE "insert into lease6 failed, status code %d"

    # Dump lease6 to output_file
    ${keaadmin} lease-dump pgsql -6 -u $db_user -p $db_password -n $db_name -d $db_scripts_dir -o $output_file
    ERRCODE=$?
    assert_eq 0 $ERRCODE "kea-admin lease-dump -6 failed, status code %d"

    # Expiration field is a "timestamp with timezone" so we need a localized reference
    # times for the machine/DB this test is running upon.
    local_timestamp1=`get_local_time "$timestamp1"`
    local_timestamp2=`get_local_time "$timestamp2"`
    local_timestamp3=`get_local_time "$timestamp3"`

    # Create the comparison file by replacing the <timestamp> tags
    # with the local reference timestamp
    sedstr="\
sed 's/<timestamp1>/$local_timestamp1/g' $ref_file | \
sed 's/<timestamp2>/$local_timestamp2/g' | \
sed 's/<timestamp3>/$local_timestamp3/g' "

    eval $sedstr >$ref_file_tmp
    ERRCODE=$?
    assert_eq 0 $ERRCODE "timestamp replacement failed, expected exit code %d, actual %d"

    # Compare the dump output to reference file, they should be identical
    cmp -s $output_file  $ref_file_tmp
    ERRCODE=$?
    assert_eq 0 $ERRCODE "dump file does not match reference file"

    # Remove the output file and temporary reference file
    rm $output_file
    rm $ref_file_tmp

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

# Upgrades an existing schema to a target newer version
# param target_version - desired schema version as "major.minor"
pgsql_upgrade_schema_to_version() {
    target_version=$1

    # Check if the scripts directory exists at all.
    if [ ! -d ${db_scripts_dir}/pgsql ]; then
        log_error "Invalid scripts directory: ${db_scripts_dir}/pgsql"
        exit 1
    fi

    # Check if there are any files in it
    num_files=$(find ${db_scripts_dir}/pgsql/upgrade*.sh -type f | wc -l)
    if [ $num_files -eq 0 ]; then
        log_error "No scripts in ${db_scripts_dir}/pgsql?"
        exit 1
    fi

    # Postgres psql does not accept pw on command line, but can do it
    # thru an env
    export PGPASSWORD=$db_password

    for script in ${db_scripts_dir}/pgsql/upgrade*.sh
    do
        if [ $version = "$target_version" ]
        then
            break;
        fi

        echo "Processing $script file..."
        sh ${script} -U ${db_user} -h ${db_host} -d ${db_name}

        version=`pgsql_version`
    done

    echo "Schema upgraded to $version"
}

# Verifies lease4_stat trigger operations on
# an new, empty database.  It inserts, updates, and
# deletes various leases, checking lease4_stat
# values along the way.
pgsql_lease4_stat_test() {
    test_start "pgsql.lease4_stat_test"

    # Let's wipe the whole database
    pgsql_wipe

    # Ok, now let's initialize the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?
    assert_eq 0 $ERRCODE "kea-admin lease-init pgsql returned non-zero status code %d, expected %d"

    # Verify lease4 stat table is present
    qry="select count(subnet_id) from lease4_stat"
    run_statement "#1" "$qry" 0

    # Insert lease4
    qry="insert into lease4 (address, subnet_id, state) values (111,1,0)"
    run_statement "#2" "$qry"

    # Assigned state count should be 1
    qry="select leases from lease4_stat where subnet_id = 1 and state = 0"
    run_statement "#3" "$qry" 1

    # Set lease state to declined
    qry="update lease4 set state = 1 where address = 111"
    run_statement "#4" "$qry"

    # Leases state count for assigned should be 0
    qry="select leases from lease4_stat where subnet_id = 1 and state = 0"
    run_statement "#5" "$qry" 0

    # Leases state count for declined should be 1
    qry="select leases from lease4_stat where subnet_id = 1 and state = 1"
    run_statement "#6" "$qry" 1

    # Delete the lease
    qry="delete from lease4 where address = 111"
    run_statement "#7" "$qry"

    # Leases state count for declined should be 0
    qry="select leases from lease4_stat where subnet_id = 1 and state = 1"
    run_statement "#8" "$qry" 0

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

# Verifies that lease6_stat triggers operate correctly
# for using a given address and lease_type.  It will
# insert a lease, update it, and delete checking the
# lease stat counts along the way.  It assumes the
# database has been created but is empty.
# param addr - address to use to add to subnet 1
# param ltype - type of lease to create
pgsql_lease6_stat_per_type() {
    addr=$1;shift;
    ltype=$1;

    # insert a lease6 for addr and ltype, state assigned
    qry="insert into lease6 (address, lease_type, subnet_id, state) values ('$addr',$ltype,1,0);"
    run_statement "#2" "$qry"

    # assigned stat should be 1
    qry="select leases from lease6_stat where subnet_id = 1 and lease_type = $ltype and state = 0";
    run_statement "#3" "$qry" 1

    # update the lease, changing state to declined
    qry="update lease6 set state = 1 where address = '$addr'"
    run_statement "#4" "$qry"

    # leases stat for assigned state should be 0
    qry="select leases from lease6_stat where subnet_id = 1 and lease_type = $ltype and  state = 0";
    run_statement "#5" "$qry" 0

    # leases count for declined state should be 1
    qry="select leases from lease6_stat where subnet_id = 1 and lease_type = $ltype and  state = 1";
    run_statement "#6" "$qry" 1

    # delete the lease
    qry="delete from lease6 where address = '$addr';"
    run_statement "#7" "$qry"

    # leases count for declined state should be 0
    qry="select leases from lease6_stat where subnet_id = 1 and lease_type = $ltype and  state = 0";
    run_statement "#6" "$qry" 0
}

# Verifies that lease6_stat triggers operation correctly
# for both NA and PD lease types, pgsql_lease6_stat_per_type()
pgsql_lease6_stat_test() {

    test_start "pgsql.lease6_stat_test"

    # Let's wipe the whole database
    pgsql_wipe

    # Ok, now let's initialize the database
    ${keaadmin} lease-init pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?

    assert_eq 0 $ERRCODE "kea-admin lease-init pgsql returned non-zero status code %d, expected %d"

    # verify lease6 stat table is present
    qry="select count(subnet_id) from lease6_stat"
    run_statement "#1" "$qry"

    # Test for address 111, NA lease type
    pgsql_lease6_stat_per_type "111" "0"

    # Test for address 222, PD lease type
    pgsql_lease6_stat_per_type "222" "1"

    # Let's wipe the whole database
    pgsql_wipe

    test_finish 0
}

# Verifies that you can upgrade from earlier version and
# lease<4/6>_stat tables will be populated based on existing
# leases and that the stat triggers work properly.
pgsql_lease_stat_upgrade_test() {
    test_start "pgsql.lease_stat_upgrade_test"

    # Let's wipe the whole database
    pgsql_wipe

    # We need to create an older database with lease data so we can
    # verify the upgrade mechanisms which prepopulate the lease stat
    # tables.
    #
    # Initialize database to scheme 1.0.
    pgsql_execute_script @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.pgsql
    assert_eq 0 $? "cannot initialize 1.0 database, expected exit code: %d, actual: %d"

    # Now upgrade to schema 2.0, this has lease_state in it
    pgsql_upgrade_schema_to_version 2.0

    # Now we need insert some leases to "migrate" for both v4 and v6
    qry=\
"insert into lease4 (address, subnet_id, state) values (111,10,0);\
 insert into lease4 (address, subnet_id, state) values (222,10,0);\
 insert into lease4 (address, subnet_id, state) values (333,10,1);\
 insert into lease4 (address, subnet_id, state) values (444,10,2);\
 insert into lease4 (address, subnet_id, state) values (555,77,0);"
    run_statement "insert v4 leases" "$qry"

    qry=\
"insert into lease6 (address, lease_type, subnet_id, state) values (111,0,40,0);\
 insert into lease6 (address, lease_type, subnet_id, state) values (222,0,40,1);\
 insert into lease6 (address, lease_type, subnet_id, state) values (333,1,40,0);\
 insert into lease6 (address, lease_type, subnet_id, state) values (444,1,50,0);\
 insert into lease6 (address, lease_type, subnet_id, state) values (555,1,50,0);\
 insert into lease6 (address, lease_type, subnet_id, state) values (666,1,40,2);"
    run_statement "insert v6 leases" "$qry"

    # Ok, we have a 2.0 database with leases. Let's upgrade it to 4.0
    ${keaadmin} lease-upgrade pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?

    #
    # First we'll verify lease4_stats are correct after migration.
    #

    # Assigned leases for subnet 10 should be 2
    qry="select leases from lease4_stat where subnet_id = 10 and state = 0"
    run_statement "#4.1" "$qry" 2

    # Assigned leases for subnet 77 should be 1
    qry="select leases from lease4_stat where subnet_id = 77 and state = 0"
    run_statement "#4.2" "$qry" 1

    # Should be no records for EXPIRED
    qry="select count(subnet_id) from lease4_stat where state = 2"
    run_statement "#4.3" "$qry" 0

    #
    # Now we'll verify v4 trigger operation for insert,update, and delete
    #

    # Insert a new lease subnet 77
    qry="insert into lease4 (address, subnet_id, state) values (777,77,0);"
    run_statement "#4.4" "$qry"

    # Assigned count for subnet 77 should be 2
    qry="select leases from lease4_stat where subnet_id = 77 and state = 0"
    run_statement "#4.5" "$qry" 2

    # Update the state of the new lease to declined
    qry="update lease4 set state = 1 where address = 777;"
    run_statement "#4.6" "$qry"

    # Assigned count for subnet 77 should be 1 again
    qry="select leases from lease4_stat where subnet_id = 77 and state = 0"
    run_statement "#4.7" "$qry" 1

    # Declined count for subnet 77 should be 1
    qry="select leases from lease4_stat where subnet_id = 77 and state = 1"
    run_statement "#4.8" "$qry" 1

    # Delete the lease.
    qry="delete from lease4 where address = 777;"
    run_statement "#4.9" "$qry"

    # Declined count for subnet 77 should be 0
    qry="select leases from lease4_stat where subnet_id = 77 and state = 1"
    run_statement "#4.10" "$qry" 0

    #
    # Next we'll verify lease6_stats are correct after migration.
    #

    # Assigned leases for subnet 40 should be 1
    qry="select leases from lease6_stat where subnet_id = 40 and lease_type = 0 and state = 0"
    run_statement "#6.1" "$qry" 1

    # Assigned (PD) leases for subnet 40 should be 1
    qry="select leases from lease6_stat where subnet_id = 40 and lease_type = 1 and state = 0"
    run_statement "#6.2" "$qry" 1

    # Declined leases for subnet 40 should be 1
    qry="select leases from lease6_stat where subnet_id = 40 and lease_type = 0 and state = 1"
    run_statement "#6.3" "$qry" 1

    # Assigned (PD) leases for subnet 50 should be 2
    qry="select leases from lease6_stat where subnet_id = 50 and lease_type = 1 and state = 0"
    run_statement "#6.4" "$qry" 2

    # Should be no records for EXPIRED
    qry="select count(subnet_id) from lease4_stat where state = 2"
    run_statement "#6.5" "$qry" 0

    #
    # Finally we'll verify v6 trigger operation for insert,update, and delete
    #

    # Insert a new lease subnet 50
    qry="insert into lease6 (address, subnet_id, lease_type, state) values ('777',50,1,0)"
    run_statement "#6.5" "$qry"

    # Assigned count for subnet 50 should be 3
    qry="select leases from lease6_stat where subnet_id = 50 and lease_type = 1 and state = 0"
    run_statement "#6.6" "$qry" 3

    # Update the state of the new lease to expired
    qry="update lease6 set state = 2 where address = '777';"
    run_statement "#6.7" "$qry"

    # Assigned count for subnet 50 should be 2 again
    qry="select leases from lease6_stat where subnet_id = 50 and lease_type = 1 and state = 0"
    run_statement "#6.8" "$qry" 2

    # Delete another PD lease.
    qry="delete from lease6 where address = '555'"
    run_statement "#6.9" "$qry"

    # Assigned leases for subnet 50 should be 1
    qry="select leases from lease6_stat where subnet_id = 50 and lease_type = 1 and state = 0"
    run_statement "#6.10" "$qry" 1

    # Let's wipe the whole database
    pgsql_wipe
}

# Verifies that you can upgrade from earlier version and
# that unused subnet ID values in hosts and options tables are
# converted to NULL.
pgsql_unused_subnet_id_test() {
    test_start "pgsql.unused_subnet_id_test"

    # Let's wipe the whole database
    pgsql_wipe

    # We need to create an older database with lease data so we can
    # verify the upgrade mechanisms which prepopulate the lease stat
    # tables.
    #
    # Initialize database to scheme 1.0.
    pgsql_execute_script @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.pgsql
    assert_eq 0 $? "cannot initialize 1.0 database, expected exit code: %d, actual: %d"

    # Now upgrade to schema 4.0
    pgsql_upgrade_schema_to_version 4.0

    # Now we need insert some hosts to "migrate" for both v4 and v6
    qry=\
"insert into hosts (dhcp_identifier_type, dhcp_identifier, dhcp4_subnet_id, dhcp6_subnet_id, hostname)\
   values (0, '0123456', 0, 0, 'both'); \
 insert into hosts (dhcp_identifier_type, dhcp_identifier, dhcp4_subnet_id, dhcp6_subnet_id, hostname)\
   values (0, '1123456', 4, 0, 'v4only');
 insert into hosts (dhcp_identifier_type, dhcp_identifier, dhcp4_subnet_id, dhcp6_subnet_id, hostname)\
   values (0, '2123456', 0, 6, 'v6only');\
 insert into hosts (dhcp_identifier_type, dhcp_identifier, dhcp4_subnet_id, dhcp6_subnet_id, hostname) \
   values (0, '3123456', 4, 6, 'neither');"

    run_statement "insert hosts" "$qry"

    # Now we need insert some options to "migrate" for both v4 and v6
    qry=\
"insert into dhcp4_options (code, dhcp4_subnet_id, scope_id) values (1, 4, 0);\
 insert into dhcp4_options (code, dhcp4_subnet_id, scope_id) values (2, 0, 0);\
 insert into dhcp6_options (code, dhcp6_subnet_id, scope_id) values (1, 6, 0);\
 insert into dhcp6_options (code, dhcp6_subnet_id, scope_id) values (2, 0, 0);"

    run_statement "insert options" "$qry"

    # Ok, we have a 4.0 database with hosts and options. Let's upgrade it to 5.0
    ${keaadmin} lease-upgrade pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    ERRCODE=$?

    # Upgrade should succeed
    assert_eq 0 $ERRCODE "upgrade failed"

    # Two hosts should have null v4 subnet ids
    qry="select count(host_id) from hosts where dhcp4_subnet_id is null;"
    run_statement "#hosts.1" "$qry" 2

    # Two hosts should have v4 subnet ids = 4
    qry="select count(host_id) from hosts where dhcp4_subnet_id = 4;"
    run_statement "#hosts.2" "$qry" 2

    # Two hosts should have null v6 subnet ids
    qry="select count(host_id) from hosts where dhcp6_subnet_id is null;"
    run_statement "#hosts.3" "$qry" 2

    # Two hosts should should have v6 subnet ids = 6
    qry="select count(host_id) from hosts where dhcp6_subnet_id = 6;"
    run_statement "#hosts.4" "$qry" 2

    # One option should have null v4 subnet id
    qry="select count(option_id) from dhcp4_options where dhcp4_subnet_id is null;"
    run_statement "#options.1" "$qry" 1

    # One option should have v4 subnet id = 4
    qry="select count(option_id) from dhcp4_options where dhcp4_subnet_id = 4;"
    run_statement "#options.2" "$qry" 1

    # One option should have null v6 subnet id
    qry="select count(option_id) from dhcp6_options where dhcp6_subnet_id is null;"
    run_statement "#options.3" "$qry" 1

    # One option should have v4 subnet id = 6
    qry="select count(option_id) from dhcp6_options where dhcp6_subnet_id = 6;"
    run_statement "#options.4" "$qry" 1

    # Let's wipe the whole database
    pgsql_wipe
}


pgsql_lease_init_test
pgsql_lease_version_test
pgsql_upgrade_test
pgsql_lease4_dump_test
pgsql_lease6_dump_test
pgsql_lease4_stat_test
pgsql_lease6_stat_test
pgsql_lease_stat_upgrade_test
pgsql_unused_subnet_id_test
