#!/bin/sh

# Copyright (C) 2014-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"

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

cql_wipe() {
    # Wipe the database.
    cql_execute_script $db_scripts_dir/cql/dhcpdb_drop.cql
    assert_eq 0 $? "drop table query failed, exit code %d, expected %d"
}

cql_lease_init_test() {
    test_start "cql.init"

    # Wipe the database.
    cql_wipe

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

    # Verify that all the expected tables exist

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

    # Check lease4 table
    cql_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
    cql_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
    cql_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
    cql_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 "Making sure keyspace creation fails the second time..."
    $keaadmin lease-init cql -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"

    # Wipe the database.
    cql_wipe

    test_finish 0
}

cql_lease_version_test() {
    test_start "cql.version"

    # Wipe the database.
    cql_wipe

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

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

    # Wipe the database.
    cql_wipe

    test_finish 0
}

cql_upgrade_test() {
    test_start "cql.upgrade"

    # Wipe the database.
    cql_wipe

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

    $keaadmin lease-upgrade cql -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"

    # Wipe the database.
    cql_wipe

    test_finish 0
}

cql_lease4_dump_test() {
    test_start "cql.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/cql.lease4_dump_test.output.csv"
    tmp_file="$output_file.tmp"

    ref_file="$test_dir/data/cql.lease4_dump_test.reference.csv"

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

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

    # Wipe the database.
    cql_wipe

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

    # Insert the reference record.
    # -1073741302 corresponds to 192.0.2.10
    # -1073741301 corresponds to 192.0.2.11
    # -1073741300 corresponds to 192.0.2.12
    # 1430694930 corresponds to 2015-04-04 01:15:30
    # 1433464245 corresponds to 2015-05-05 02:30:45
    # 1436173267 corresponds to 2015-06-06 11:01:07
    insert_cql="\
INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\
 fqdn_fwd, fqdn_rev, hostname, state, user_context)\
 VALUES(-1073741302,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\
 'one.example.com', 0, '');\
INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\
 fqdn_fwd, fqdn_rev, hostname, state, user_context)\
 VALUES(-1073741301,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1, '');\
INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\
 fqdn_fwd, fqdn_rev, hostname, state, user_context)\
 VALUES(-1073741300,textAsBlob('22'),NULL,40,1436173267,50,true,true,\
 'three.example.com', 2, '');"

    cql_execute "$insert_cql"
    assert_eq 0 $? "insert into lease4 failed, expected exit code %d, actual %d"

    # Dump lease4 to output_file.
    $keaadmin lease-dump cql -4 -u $db_user -p $db_password -n $db_name -d $db_scripts_dir -o $output_file
    assert_eq 0 $? "kea-admin lease-dump -4 failed, expected exit code %d, actual %d"

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

    # remove the output file.
    rm $output_file

    # Wipe the database.
    cql_wipe

    test_finish 0
}

cql_lease6_dump_test() {
    test_start "cql.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/cql.lease6_dump_test.output.csv"
    tmp_file="$output_file.tmp"

    ref_file="$test_dir/data/cql.lease6_dump_test.reference.csv"

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

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

    # Wipe the database.
    cql_wipe

    # Create the database.
    $keaadmin lease-init cql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
    assert_eq 0 $? "could not create database, expected exit code %d, actual %d"

    # Insert the reference record.
    # 1430694930 corresponds to 2015-04-04 01:15:30
    # 1433464245 corresponds to 2015-05-05 02:30:45
    # 1436173267 corresponds to 2015-06-06 11:01:07
    insert_cql="\
INSERT INTO lease6(address, duid, valid_lifetime, expire, subnet_id,\
 pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname,\
 hwaddr, hwtype, hwaddr_source, state, user_context)\
 VALUES('2001:db8::10',textAsBlob('20'),30,1430694930,40,50,1,60,70,true,true,\
 'one.example.com',textAsBlob('80'),90,16,0,'');\
INSERT INTO lease6(address, duid, valid_lifetime, expire, subnet_id,\
 pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname,\
 hwaddr, hwtype, hwaddr_source, state, user_context)\
 VALUES('2001:db8::11',NULL,30,1433464245,40,50,1,60,70,true,true,\
 '',textAsBlob('80'),90,1,1,'');\
INSERT INTO lease6(address, duid, valid_lifetime, expire, subnet_id,\
 pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname,\
 hwaddr, hwtype, hwaddr_source, state, user_context)\
 VALUES('2001:db8::12',textAsBlob('21'),30,1436173267,40,50,1,60,70,true,true,\
 'three.example.com',textAsBlob('80'),90,4,2,'');"

    cql_execute "$insert_cql"
    assert_eq 0 $? "insert into lease6 failed, expected exit code %d, actual %d"

    # Dump lease4 to output_file.
    $keaadmin lease-dump cql -6 -u $db_user -p $db_password -n $db_name -d $db_scripts_dir -o $output_file
    assert_eq 0 $? "kea-admin lease-dump -6 failed, status code %d"

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

    # remove the output file.
    rm $output_file

    # Wipe the database.
    cql_wipe

    test_finish 0
}

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

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

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

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

        echo "Processing $script file..."
        sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
        version=`cql_version`
    done

    echo "Schema upgraded to $version"
}

# Verifies that you can upgrade from an earlier version and
# that unused subnet ID values in hosts and options tables are
# converted to -1
cql_unused_subnet_id_test() {
    test_start "cql.unused_subnet_id_test"

    # Let's wipe the whole database
    cql_wipe

    # We need to create an older database with lease data so we can
    # verify the upgrade mechanisms which convert subnet id values
    #
    # Initialize database to schema 1.0.
    cql_execute_script @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.cql

    # Now upgrade to schema 2.0, the version just before global HRs
    cql_upgrade_schema_to_version 2.0

    # Now we need insert some hosts to "migrate" for both v4 and v6
    qry=\
"insert into host_reservations (id, host_identifier_type, host_identifier, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id)\
   values (1, 0, textAsBlob('0123456'), 0, 0, 0);\
 insert into host_reservations (id, host_identifier_type, host_identifier, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id)\
   values (2, 0, textAsBlob('1123456'), 4, 0, 4);\
 insert into host_reservations (id, host_identifier_type, host_identifier, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id)\
   values (3, 0, textAsBlob('2123456'), 0, 6, 6);\
 insert into host_reservations (id, host_identifier_type, host_identifier, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id)\
   values (4, 0, textAsBlob('3123456'), 4, 6, 0);\
 insert into host_reservations (id, host_identifier_type, host_identifier, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id)\
   values (5, 0, textAsBlob('3123456'), -1, 6, 6);"

    cql_execute "$qry"
    assert_eq 0 $? "insert hosts failed, expected exit code: %d, actual: %d"

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

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

    test_dir="@abs_top_srcdir@/src/bin/admin/tests"
    ref_file="$test_dir/data/cql.subnet_id_test.reference.csv"

    output_dir="@abs_top_builddir@/src/bin/admin/tests"
    export_file="$output_dir/data/cql.subnet_id_test.csv"

    # Fetch host_reservation data for comparison
    echo "Exporting host_reservation data to $export_file ..."

    qry=\
"select id, host_ipv4_subnet_id, host_ipv6_subnet_id, option_subnet_id from\
 host_reservations where id in(1,2,3,4,5);"

    cql_execute "$qry" >$export_file
    assert_eq 0 $? "insert hosts failed, expected exit code: %d, actual: %d"
    # Compare the dump output to reference file, they should be identical.
    cmp -s $export_file  $ref_file
    assert_eq 0 $? "export file does not match reference file, expected exit code %d, actual %d"

    # remove the output file.
    rm $export_file

    # Wipe the database.
    cql_wipe

    # Report test success.
    test_finish 0
}


# Run tests.
cql_lease_init_test
cql_lease_version_test
cql_upgrade_test
cql_lease4_dump_test
cql_lease6_dump_test
cql_unused_subnet_id_test
