#!/bin/sh
# tests with rpm installations (--justdb is used)

. ./sh/lib/setup
. ./sh/lib/repo-setup
. ./sh/lib/solver-setup
. ./sh/lib/rpm-setup

ORIGREPO=
DESTINATION_REPO=
DEPENDENCY_SOLVER=3

setUp() {
    rpm_up

    is_rpm_testing_off && return
    # provide /bin/sh auto requirement
    rpm_build_installed sh -p /bin/sh
}

tearDown() {
    is_rpm_testing_off && return
    rpm_down
}

build() {
    build_package $REPO $@
}

build_installed() {
    rpm_build_installed $@
}

try_install() {
  rpm_install "$@"
}

testRPMdbcache() {
    skip_if_rpm_testing_off && return

    build foo

    local op=""
    is_verbose_mode && op="-v"

    msgn "create rpmdb cache with dirindex"
    msgn "$RAW_POLDEK -Oauto_directory_dependencies=y --root $DESTINATION_REPO $op --cmd ls"
    $RAW_POLDEK -Oauto_directory_dependencies=y --root $DESTINATION_REPO $op --cmd ls >/dev/null
    local rpmdb_cachedirname="$(echo $DESTINATION_REPO | sed -e 's|^/||' -e 's|/|.|g').var.lib.rpm"
    local suffix="rpmdbcache$(echo $DESTINATION_REPO | sed 's|/|.|g').var.lib.rpm"

    # check presence of dbcache
    for i in zst md zst.md5; do
        local name="packages.$suffix.$i"
        [ -f "$CACHEDIR/$name" ] || fail "missing expected $name in $CACHEDIR"
    done

    # check presence of dbcache's dirindex
    for i in tndb tndb.md5; do
        local name="dirindex.$suffix.$i"
        [ -f "$CACHEDIR/$name" ] || fail "missing expected $name in $CACHEDIR"
    done

    local dirindex_path="$CACHEDIR/$rpmdb_cachedirname/dirindex.rpmdb.tndb"
    local md5=$(md5sum $dirindex_path | cut -f1 -d' ')


    # will die (we're in test mode) if dirindex is missing
    $RAW_POLDEK -Oauto_directory_dependencies=y --st dir -s $REPO --root $DESTINATION_REPO $op --cmd ls -u >/dev/null
    assertEquals "died" "$?" "0"
    msgn "install a"
    local md=$(md5sum $dirindex_path | cut -f1 -d' ')
    assertEquals "dirindex changed" "$md5" "$md"

    build a "1-1"

    try_install a "a-1-1" ""

    msgn "update dirindex"
    # should load rpmdb and update dirindex
    $RAW_POLDEK -Oauto_directory_dependencies=y --st dir -s $REPO --root $DESTINATION_REPO $op --cmd ls -u >/dev/null

    local md=$(md5sum $dirindex_path | cut -f1 -d' ')
    if [ "$md5" = "$md" ]; then
        fail "$dirindex_path: dirindex not changed ($md5)"
    fi
}

# the dirindex is stamped with the database mtime; if it is made in the
# same second as a later database change, it must not be considered current
testRPMdbcacheDirindexSameSecond() {
    skip_if_rpm_testing_off && return

    local rpmdb_cachedirname="$(echo $DESTINATION_REPO | sed -e 's|^/||' -e 's|/|.|g').var.lib.rpm"

    build a

    local dbfiles="$DESTINATION_REPO$($RPM --eval %_dbpath)/*"
    local mtime=$(( $(date +%s) + 3600 ))
    $SUDO touch -d @$mtime $dbfiles || fail "cannot touch rpmdb files"

    $RAW_POLDEK -Oauto_directory_dependencies=y --st dir -s $REPO \
        --root $DESTINATION_REPO --cmd ls -u >/dev/null

    local dirindex_path="$CACHEDIR/$rpmdb_cachedirname/dirindex.rpmdb.tndb"
    [ -f "$dirindex_path" ] || fail "missing dirindex $dirindex_path"

    local mtime_1="$((mtime - 1))"
    local mtime_di=$(stat -c %Y "$dirindex_path")

    assertEquals "dirindex mtime differ ($mtime_1 != $mtime_di)" "$mtime_1" "$mtime_di"
    local md5=$(md5sum "$dirindex_path" | cut -f1 -d' ')

    try_install a "a-1-1" ""
    $SUDO touch -d @$mtime $dbfiles || fail "cannot touch rpmdb files"

    $RAW_POLDEK -Oauto_directory_dependencies=y --st dir -s $REPO \
        --root $DESTINATION_REPO --cmd ls -u >/dev/null

    local md=$(md5sum "$dirindex_path" | cut -f1 -d' ')
    if [ "$md5" = "$md" ]; then
        fail "$dirindex_path: dirindex not updated"
    fi
    assertEquals "dirindex mtime after update" "$((mtime - 1))" "$(stat -c %Y "$dirindex_path")"
}

# rpm changes the database in the second poldek cached it
testRPMdbcacheSameSecond() {
    skip_if_rpm_testing_off && return

    # a database mtime ahead of the clock: changed "just now" for any cache
    # made before it, however long the run takes
    local dbfiles="$DESTINATION_REPO$($RPM --eval %_dbpath)/*"
    local mtime=$(( $(date +%s) + 3600 ))
    $SUDO touch -d @$mtime $dbfiles

    $RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I >/dev/null  # caches it

    rpm_build_installed b 1-1
    $SUDO touch -d @$mtime $dbfiles  # changed within the same second

    local n=$($RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I | grep -c '^b-1-1')
    assertEquals "b-1-1 not listed as installed" "1" "$n"
}

# another program changes the database while poldek runs, in the second
# poldek read it in; with the database an hour old, poldek exits long after
testRPMdbcacheChangedWhileRunning() {
    skip_if_rpm_testing_off && return

    local dbfiles="$DESTINATION_REPO$($RPM --eval %_dbpath)/*"
    local mtime=$(( $(date +%s) - 3600 ))
    $SUDO touch -d @$mtime $dbfiles

    mkdir -p $DESTINATION_REPO/RPMS/
    rm -f $DESTINATION_REPO/RPMS/*.rpm
    build_package $DESTINATION_REPO/RPMS/ b 1-1
    local change="$TMPDIR/08-rpm-change.sh"
    echo "$RPM -i --quiet --justdb $DESTINATION_REPO/RPMS/*.rpm && $SUDO touch -d @$mtime.5 $dbfiles" > $change

    printf 'cd /installed\nls\n!sh %s\nquit\n' "$change" |
        timeout 60 script -qec "$RAW_POLDEK --root $DESTINATION_REPO --shell" /dev/null >/dev/null
    $RPM --quiet -q b || fail "b: rpm installation failed"

    local n=$($RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I | grep -c '^b-1-1')
    assertEquals "b-1-1 not listed as installed" "1" "$n"
}

# another program installs a package during a shell session that read the
# installed packages from the cache, then the session installs one
testRPMdbcacheOwnInstallAfterChange() {
    skip_if_rpm_testing_off && return

    build c 1-1
    $RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I >/dev/null  # caches it

    mkdir -p $DESTINATION_REPO/RPMS/
    rm -f $DESTINATION_REPO/RPMS/*.rpm
    build_package $DESTINATION_REPO/RPMS/ b 1-1
    local dbfiles="$DESTINATION_REPO$($RPM --eval %_dbpath)/*"
    local change="$TMPDIR/08-rpm-change.sh" age="$TMPDIR/08-rpm-age.sh"
    echo "$RPM -i --quiet --justdb $DESTINATION_REPO/RPMS/*.rpm" > $change
    echo "$SUDO touch -d '-1 hour' $dbfiles" > $age  # as if the session went on long

    printf 'cd /installed\nls\n!sh %s\ncd /all-avail\ninstall --justdb c\n!sh %s\nquit\n' \
           "$change" "$age" |
        timeout 60 script -qec "$RAW_POLDEK --st dir -s $REPO --root $DESTINATION_REPO --shell" /dev/null >/dev/null
    $RPM --quiet -q b c || fail "b, c: installation failed"

    local n=$($RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I | grep -cE '^(b|c)-1-1')
    assertEquals "b-1-1 and c-1-1 not listed as installed" "2" "$n"
}

# rpm --rebuilddb renumbers the database records, so an upgraded package can
# get the record number of the version it replaced
testRPMdbcacheRebuilddb() {
    skip_if_rpm_testing_off && return

    rpm_build_installed b 1-1
    $RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I >/dev/null  # caches it

    rm -f $DESTINATION_REPO/RPMS/*.rpm
    build_package $DESTINATION_REPO/RPMS/ b 2-1
    $RPM -U --quiet --justdb $DESTINATION_REPO/RPMS/*.rpm
    $RPM --rebuilddb

    local n=$($RAW_POLDEK --root $DESTINATION_REPO --cmd ls -I | grep -c '^b-2-1')
    assertEquals "b-2-1 not listed as installed" "1" "$n"
}

# e.g. openssl multiple instances
testUpgradeMultipleInstalled() {
    skip_if_rpm_testing_off && return
    msgn "Preparing repositories..."
    build_installed a 1-1
    build_installed a 2-1
    build_installed a 3-1

    build a 4
    try_install a "a-4-1" "a-3-1"
}

testUpgradeMultipleInstalledWithDeps() {
    skip_if_rpm_testing_off && return
    msgn "Preparing repositories..."
    build_installed a 0.9.8c-1
    build_installed a 1.0.0o-1
    build_installed a 1.1.1j-1

    for i in b10 c10 d10; do
        build_installed $i 0.1-0.1 -r "'a = 1.0.0o'"
    done

# TODO
#    for i in b11 c11; do
#        build_installed $i 1.0-1 -r "'a = 1.1'"
#    done

    build a 1.1.1k-1
    try_install a "a-1.1.1k-1" "a-1.1.1j-1"
}

# poldek's rpmlog() hides rpm's notices such as "<file>: digests OK"
testInstallRpmNoticesFiltered() {
    skip_if_rpm_testing_off && return
    build a 1-1

    typeset out=$($POLDEK_INSTALL -uv a 2>&1)
    echo "$out" | grep -q 'digests OK' && fail "rpm notices are not filtered: $out"
    rpm_state_check "a" ""
}

# desc -L and ls -S take as new the changelog entries dated after the day
# the installed version was built: entries carry their date only, and rpm
# stores it as noon, later than a build made that morning
testChangelogAfterInstalledBuildDay() {
    skip_if_rpm_testing_off && return

    export SOURCE_DATE_EPOCH=$(date -u -d '2020-04-25 06:00' +%s)
    build_installed a 1-1 -l "'Sat Apr 25 2020|fix for CVE-2020-0001'"
    build_installed b 1-1
    unset SOURCE_DATE_EPOCH

    build a 2-1 -l "'Sun Apr 26 2020|a 2 entry'" -l "'Sat Apr 25 2020|fix for CVE-2020-0001'"
    build b 2-1 -l "'Sun Apr 26 2020|fix for CVE-2020-0002'"

    local P="$RAW_POLDEK --st dir -s $REPO --root $DESTINATION_REPO"
    local out=$($P --cmd desc -L a 2>&1)
    echo "$out" | grep -q 'a 2 entry' || fail "a-2-1: the new entry not shown: $out"
    echo "$out" | grep -q 'CVE-2020-0001' && fail "a-2-1: a-1-1's own entry shown as new: $out"

    out=$($P --cmd ls -S 2>&1)
    echo "$out" | grep -q '^a-2-1' && fail "a-2-1 listed for a fix a-1-1 has: $out"
    echo "$out" | grep -q '^b-2-1' || fail "b-2-1 not listed for its new fix: $out"
}

# not implemented yet
xtestUpgradeMultipleInstalledIndir() {
    skip_if_rpm_testing_off && return
    msgn "Preparing repositories..."
    build_installed a 1.0-1
    build_installed a 1.1-1

    build a 1.2-1
    build b 1-1 -r "'a = 1.2'"

    try_install b-1-1 "a-1.2" "a-1.1-1"
}


# wip: want to keep old kernel(s) but install new one
xtestKeepUpgrade() {
    skip_if_rpm_testing_off && return

    msgn "Preparing repositories..."
    local prefix="kernel"
    local pkg="${prefix}-5.4"
    for i in 1; do
        #build_installed $prefix-headers 8
        build_installed $pkg $i
        build_installed "${pkg}-drm" $i -r "'$pkg = $i'" # -r "'$prefix-headers = 8'"
    done

    #build $prefix-headers 9
    build $pkg 3
    build "${pkg}-drm" 3 -r "'$pkg = 3'" # -r "'$prefix-headers = 9'"

    try_install $pkg-drm "$pkg-3,$pkg-drm-3" ""
    #try_install $pkg-drm "$pkg-3,$pkg-drm-3,$prefix-headers-9" "$prefix-headers-8"
}

. ./sh/lib/shunit2
