#!/bin/sh
# $Id$

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

ORIGREPO=
DESTINATION_REPO=
DEPENDENCY_SOLVER=3

#tearDown() {
#    [ -n "$REPO" ] && rm -f $REPO/*.*
#}

setUp() {
    [ -z "$ORIGREPO" ] && ORIGREPO=$REPO
    [ -z "$ORIGREPO" ] && fail "empty REPO env variable"
    rm -rf $ORIGREPO/*

    REPO="$ORIGREPO/src"
    REPO2="$ORIGREPO/src2"
    DESTINATION_REPO="$ORIGREPO/dest";

    rm -rf $REPO $REPO2 $DESTINATION_REPO

    mkdir -p $REPO || fail "mkdir $REPO failed"
    mkdir -p $REPO2 || fail "mkdir $REPO2 failed"
    mkdir -p $DESTINATION_REPO || fail "mkdir $DESTINATION_REPO failed"

    # provide /bin/sh auto requirement
    build_installed sh -p /bin/sh

    RAW_POLDEK="$POLDEK_NOCONF -Odependency_solver=$DEPENDENCY_SOLVER --noask"
    POLDEK_INSTALL="$RAW_POLDEK --st dir -s $REPO --st dir -s $REPO2 --dt dir --destination $DESTINATION_REPO"
}

build() {
   build_package $REPO $@
}

build2() {
   build_package $REPO2 $@
}

build_installed() {
   build_package $DESTINATION_REPO $@
}

# try to install package and check result
# usage: try_install <package> <expected installed> [<expected removed>] [<extra poldek switches>]
try_install() {
  try_install_package "dir" -uvt $@
}

try_install_a() {
    try_install "a" $@
}

# 'c' has unmet requirement
testChooseTheRightAlternative_1() {
  build a -r "CAP"
  build c -p "CAP" -r "unmetreq"
  build d -p "CAP"
  try_install_a "a,d"
}

# 'd' should be choosen instead of non-resolvable 'c'
testChooseTheRightAlternative_2() {
  build a -r "b"
  build b -r "CAP"
  build c -p "CAP" -r "unmetreq"
  build d -p "CAP"
  try_install_a "a,b,d"
}

# as above, but 'c' has more (solvable) requirements
testChooseTheRightAlternative_3() {
  build a -r "b"
  build b -r "CAP"
  build c -p "CAP" -r "foo" -r "bar" -r "unmetreq" -r "zfoo"
  build d -p "CAP"
  build foo
  build bar
  build zfoo
  try_install_a "a,b,d"
}

# first, but wrong resolved set is: a,b,c,e,g
testChooseTheRightAlternative_4() {
  build a  -r "b"
  build b  -r "CAP"

  build c  2-1 -r "e" -p "CAP"
  build d  -r "f" -p "CAP"

  build e  -r "g"
  build f  2-1 -r "h"

  build g  2-1 -r "unmetreq"
  build h

  try_install_a "a,b,d,f,h"
}


# package 'x' provides all 'a' requirements
testChooseMoreAccuratePackage() {
  build a -r "b" -r "c" -r "d" -r "x"
  build b -p "AA" -p "BB"
  build c
  build d
  build x -p "b" -p "c" -p "d"

  try_install_a "a,x"
}

# lp#1722104
testChooseMoreAccurateOrphanReq() {
    msgn "Preparing repositories..."
    build_installed a 1-1 -p "liba.so"
    build_installed b 1-1 -r "liba.so"

    build a 1-1 -p "liba.so"
    build a 2-2 -p "liba.so"
    build b 2-2 -r "liba.so" -r "'a = 2'"

    msgn "Upgrade"
    try_install b-2-2 "a-2-2,b-2-2" "a-1-1,b-1-1"
}


# package 'c' conflicts with 'a'
testSkipConflictedAlternative() {
  build a -r "BB" -r "CC"
  build b -p "BB" -p "CC" -c "a"
  build c -p "BB" -p "CC"

  try_install_a "a,c"
}

# b-1-1 meets all 'a' requirements
testRedundantRequirement() {
  build a -r "b" -r "'b = 1'"
  build b 2-1
  build b 1-1
  try_install_a "a,b\-1"
}

# if packages "bar" and "baz" have Obsoletes: foo, Provides: foo, Conflicts: foo,
# then librpm knows that you can only have "bar" or "baz" but not both
testRpmOrgMutualExclusive() {
    build_installed bar -o foo -p foo -c foo
    build baz -o foo -p foo -c foo

    try_install "baz" "baz" "bar"
}

testRpmOrgMutualExclusive_2() {
    build_installed baz -o foo -p foo -c foo
    build baz -v 2 -o foo -p foo -c foo

    try_install "baz" "baz" "baz"
}


# suggested packages should be installed
testSuggestsAll() {
    build_installed suggested
    build a -s "suggested" -s "b" -s "c"
    build b
    build c

    msgn "All suggested packages"
    POLDEK_TESTING_WITH_SUGGESTS="all" # choose all suggested packages
    export POLDEK_TESTING_WITH_SUGGESTS
    try_install_a "a,b,c"
}

# suggested packages should be installed
testSuggestsSome() {
    build_installed suggested
    build a -s "suggested" -s "b" -s "c"
    build b
    build c

    msgn "Some suggested packages"
    POLDEK_TESTING_WITH_SUGGESTS="b" # choose b only
    export POLDEK_TESTING_WITH_SUGGESTS
    try_install_a "a,b"
    POLDEK_TESTING_WITH_SUGGESTS=
}

testUpgradeSet() {
    msgn "Preparing repositories..."
    prev_i=
    for i in b c d e f a; do
        build_installed $i 1-1
        if [ -z "$prev_i" ]; then
           build_installed $i 1-1
           build $i 2-2
        else
           build_installed $i 1-1 -r "'$prev_i = 1-1'"
           build $i 2-2 -r "'$prev_i = 2-2'"
        fi
        prev_i=$i
    done

    try_install_a "a,b,c,d,e,f"
}

# all 'a*' must be upgraded at once
testUpgradeGreedy() {
    msgn "Preparing repositories..."
    for i in "1-1" "2-2"; do
        build a $i
        build a-devel $i -r "'a = $i'"
        build a-static $i -r "'a-devel = $i'"
    done
    mv $REPO/a*1-1*.rpm $DESTINATION_REPO || fail "mv failed"
    try_install a "a,a-devel,a-static"
    try_install a-devel "a,a-devel,a-static"
    try_install a-static "a,a-devel,a-static"
}

# should honour --greedy option
testGreedyOnOff() {
    msgn "Preparing repositories..."
    v=1-1
    build_installed foo $v -p "CAP"
    build_installed bar $v -r "CAP"

    v=2-2
    build foo $v
    build bar $v
    build baz 1-1 -p "CAP"

    msgn "Greedy..."
    try_install foo "foo,bar" "foo,bar" --greedy=yes
    msgn "Not so greedy..."
    try_install foo "foo,baz" "foo" --greedy=no
}

# should be greedy on unmet dependecies
testBeGreedyOnUnmetDeps() {
    msgn "Preparing repositories..."
    v=1-1
    build_installed foo $v -p "CAP"
    build_installed bar $v -r "CAP"

    v=2-2
    build foo $v
    build bar $v

    try_install foo "foo,bar" "foo,bar" --greedy=yes
}


# bar obsoletes foo
testUpgradeObsolete() {
    msgn "Preparing repositories..."
    build_installed a 1-1
    build_installed a-devel 1-1 -r "'a = 1-1'"
    build_installed a-static 1-1 -r "'a-devel = 1-1'"
    build_installed foo 1-1 -r "'a = 1-1'" -p "FOO" -o "FOO"

    build a 2-2
    build a-devel 2-2 -r "'a = 2-2'"
    build a-static 2-2 -r "'a-devel = 2-2'"
    build afoo 1-1 -p "FOO" -o "FOO" -o foo
    build bar 1-1 -o "foo"

    try_install a "a,a-devel,a-static,bar" "a,a-devel,a-static,foo"
}

testUpgradeMultilib() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    for i in i686 x86_64; do
        build_installed a 1-1 -a $i -f "/hello.$i"
        build_installed a-devel 1-1 -r "'a = 1'" -a $i # -f "/usr/include/foo.h"
        build_installed a-static 1-1 -r "'a = 1'" -a $i -f "/sbin/hello.$i"

        build a 2-2 -a $i -f "/hello.$i"
        build a-devel 2-2 -r "'a = 2-2'" -a $i # -f "/usr/include/foo.h"
        build a-static 2-2 -r "'a = 2-2'" -a $i -f "/sbin/hello.$i"
    done
    rm -f $DESTINATION_REPO/a-devel*i686* # remove duplicated uncolored package

    msgn "Multilib upgrades"
    try_install a-2-2.x86_64 "a-2-2.x86_64" "a-1-1.x86_64"

    try_install a-devel-2-2.x86_64 "a-2-2.x86_64,a-devel-2-2.x86_64" \
                                   "a-1-1.x86_64,a-devel-1-1.x86_64"

    try_install a-devel-2-2.i686 "a-2-2.i686,a-devel-2-2.i686" \
                                 "a-1-1.i686,a-devel-1-1.x86_64"

    msgn "Testing multilib upgrade-dist"
    runpoldek --upgrade-dist
    n=$(ls $DESTINATION_REPO/a* | grep 1-1 | wc -l)
    assertEquals "not all packages were upgraded by upgrade-dist" "$n" "0"

    # Multilib upgrade uncolored package (arch flip-flop regardless of arch)
    try_install a-devel-2-2.i686 "a-devel-2-2.i686" "a-devel-2-2.x86_64"

    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

# https://bugs.pld-linux.org/show_bug.cgi?id=83
testUpgradeMultilibOneTransactionForSamePackagesDifferentSource() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    for i in i686 x86_64; do
        build_installed FooBar 1-1 -a $i -f "/hello.$i" -f "/README"
    done
    build  FooBar 2-2 -a i686 -f "/hello.i686" -f "/README"
    build2 FooBar 2-2 -a x86_64 -f "/hello.x86_64" -f "/README"

    msgn "Up"
    try_install FooBar "FooBar-2-2.i686,FooBar-2-2.x86_64" "FooBar-1-1.i686,FooBar-1-1.x86_64"

    #"a-2-2.x86_64" "a-1-1.x86_64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

# Similar to testUpgradeOrphanIfItResolvesReq but obsoleted by different package
# http://lists.pld-linux.org/mailman/pipermail/pld-users-pl/2015-November/078844.html
testUpgradeOrphanByObsoletes() {
    msgn "Preparing repositories..."
    build_installed a -r "'a-lib = 1'" # udev
    build_installed a-lib              # udev-lib
    build_installed b -r "'a-lib = 1'" # udev-glib

    build a 2-2 -r "'a-lib = 2'"
    build a-lib 2-2
    build c -r "'a-lib'" -o "'b < 2'"  # libgudev

    msgn "Upgrade"
    try_install a "a-2,a-lib-2,c-1" "a-1,a-lib-1,b-1"
}

buildUpgradeOrphanRepos() {
    build_installed a-foo -r "'a-lib = 1'" -p "FOO"
    build_installed a-lib
    build_installed b -r "FOO"

    build a-foo 2-2 -r "'a-lib = 2'" -o "a-bar" -p "FOO"
    build a-bar 2-2 -r "'a-lib = 2'" -o "a-foo"
    build a-lib 2-2
}

# orphaned b should be upgraded as b-2-2 resolves missed FOO
testUpgradeOrphanIfItResolvesReq() {
    msgn "Preparing repositories..."
    buildUpgradeOrphanRepos
    build b 2-2

    msgn "Upgrade"
    try_install a-bar "a-bar-2,a-lib-2,b-2" "a-foo-1,a-lib-1,b-1"
}

# orphaned b should not be upgraded as b-2-2 do not resolve missed FOO
testUpgradeOrphanNotIfItNotResolvesReq() {
    msgn "Preparing repositories..."
    buildUpgradeOrphanRepos
    build b 2-2 -r "FOO"
    build c 2-2 -p "FOO"

    msgn "Upgrade"
    try_install a-bar "a-bar-2,a-lib-2,c-2" "a-foo-1,a-lib-1"
}

# b should not be upgraded as in fact it is not an orphan
testUpgradeNotFakeOrphan() {
    msgn "Preparing repositories..."
    build_installed a 1-1
    build_installed b 1-1 -r "'a = 1.1'" # notice 1.1 not 1-1

    build a 2-2
    build b 2-2
    try_install a "a-2-2" "a-1-1"
}

# orphaned b should not be upgraded as b-2-2 do not resolve missed FOO
testUpgradeOrphanGiveUp() {
    msgn "Preparing repositories..."
    buildUpgradeOrphanRepos
    build b 2-2 -r "FOO"

    msgn "Upgrade"
    if is_verbose_mode; then
       $POLDEK_INSTALL -uvt a-bar
       msg "THE ERROR ABOVE (give up) is EXPECTED"
    fi
    $POLDEK_INSTALL -uvt a-bar | grep -q "error: FOO is required by installed b-1-1, give up"
    assertEquals "poldek should give up" "$?" "0"

}

# alternatives suggested by noarch packages should be scored by rpmArchScore
# https://bugs.pld-linux.org/show_bug.cgi?id=127
testMultilibSuggestedByNoarchShouldUseArchScore() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    build n 1-1 -a "noarch" -s "a"
    for i in i686 x86_64; do
        build a 1-1 -a $i -f "/hello.$i"
    done
    POLDEK_TESTING_WITH_SUGGESTS="all" # choose all suggested packages
    export POLDEK_TESTING_WITH_SUGGESTS
    arch=$(uname -m)
    try_install n "n-1-1.noarch,a-1-1.${arch}"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
    POLDEK_TESTING_WITH_SUGGESTS=""
}

# https://bugs.pld-linux.org/show_bug.cgi?id=117
testMultilibCandidatesAssertion() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    i=i686
    build a 2-2 -a $i -r "'a-misc = 2-2'" -f "/hello.$i"
    build a-misc 2-2 -a $i -r "'a = 2-2'" -f "/sbin/hello.$i"

    i=x86_64
    build2 a 2-2 -a $i -r "'a-misc = 2-2'" -f "/hello.$i"
    build2 a-misc 2-2 -a $i -r "'a = 2-2'" -f "/sbin/hello.$i"

    for i in i686 x86_64; do
        build_installed a 1-1 -a $i -f "/hello.$i"
        build_installed a-misc 1-1 -a $i -r "'a = 1-1'" -f "/sbin/hello.$i"
    done
    try_install a-2-2.x86_64 "a-2-2.x86_64,a-misc-2-2.x86_64" "a-1-1.x86_64,a-misc-1-1.x86_64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

# https://bugs.pld-linux.org/show_bug.cgi?id=143
testMultilibDifferentArchSameColor() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    arch=amd64
    build_installed a 1-1 -a $arch -f "/hello.x86_64"
    build_installed a-misc 1-1 -a $arch -r "'a = 1-1'" -f "/bin/hello.x86_64"

    arch=x86_64
    build a 2-2 -a $arch -f "/hello.x86_64"
    build a-misc 2-2 -a $arch -f "/sbin/hello.x86_64"

    try_install a-2-2.$arch "a-2-2.x86_64,a-misc-2-2.x86_64" "a-1-1.amd64,a-misc-1-1.amd64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

#https://bugs.pld-linux.org/show_bug.cgi?id=143#c7
testMultilibDifferentArchNoColor() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    arch=amd64
    build_installed a 1-1 -a $arch -f "/hello.x86_64"
    build_installed a-misc 1-1 -a $arch -r "'a = 1-1'" -f "/bin/hello.x86_64"
    build_installed a-devel 1-1 -a $arch -r "'a = 1-1'" -f "/bin/a.h"

    arch=x86_64
    build a 2-2 -a $arch -f "/hello.x86_64"
    build a-misc 2-2 -a $arch -f "/sbin/hello.x86_64"
    build a-devel 2-2 -a $arch -r "'a = 2-2'" -f "/bin/aa.h"
    build a-devel 2-2 -a athlon -r "'a = 2-2'" -f "/bin/aaa.h"

    # arch choice of a-devel dependends on environment (rpm/platform)
    try_install a-2-2.$arch "a-2-2.x86_64,a-misc-2-2.x86_64,a-devel-2-2" "a-1-1.amd64,a-misc-1-1.amd64,a-devel-1-1.amd64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

# XXX: fails with rpmorg, i686 and x86_64 has the same color=1??
XXXtestMultilibNoSuccesor() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    arch=x86_64
    build_installed a 1-1 -a $arch -f "/hello.$arch"
    build_installed a-misc 1-1 -a $arch -r "'a = 1-1'" -f "/bin/hello.$arch"
    build_installed a-devel 1-1 -a $arch -r "'a = 1-1'" -f "/sbin/hello.$arch"

    build a 2-2 -a $arch -f "/hello.$arch"
    build a-misc 2-2 -a $arch -f "/sbin/hello.$arch"
    build a-devel 2-2 -a $arch -r "'a = 2-2'" -f "/bin/hello.i686"
    build a-devel 2-2 -a i686 -r "'a = 2-2'" -f "/bin/hello.i686"

    if is_verbose_mode; then
       $POLDEK_INSTALL -uvt a-2-2.$arch
       msg "THE ERROR ABOVE (a = 1-1 is required by installed) is EXPECTED"
    fi
    $POLDEK_INSTALL -uvt a-2-2.$arch | grep -q "error: a = 1-1 is required by installed a-devel-1-1.x86_64"
    assertEquals "poldek should fail" "$?" "0"

    nerrors=$($POLDEK_INSTALL -uvt a-2-2.$arch | grep "^error: " | wc -l)
    assertEquals "poldek should fail with 2 error:'s" "$nerrors" "2"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}


# https://bugs.launchpad.net/poldek/+bug/299685
# poldek should allow any color -> no-color and no-color -> color upgrades
testMultilibNoColorDiffrentArchUpgrade() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    build_installed a 1-1 -a x86_64 -f "/hello.x86_64"
    build a 2-2 -a noarch -f "/hello.sh"
    try_install a-2-2.noarch "a-2-2.noarch" "a-1-1.x86_64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}

# same https://bugs.launchpad.net/poldek/+bug/299685
testMultilibNoColorToColorUpgrade() {
    ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    msgn "Preparing repositories..."
    build_installed a 1-1 -a x86_64 -f "/hello.sh"
    build a 2-2 -a amd64 -f "/hello.x86_64"
    try_install a-2-2.amd64 "a-2-2.amd64" "a-1-1.x86_64"
    POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}


# Should score orphan successors and choose best fit
testOrhpanSuccessorScore() {
    msgn "Preparing repositories..."
    build_installed a 1.0-1
    build_installed a-tools 1.0-1 -r "'a = 1.0'"

    build a 1.5-1
    build a-tools 1.5-1 -r "'a = 1.5'"

    build a 2.0-1
    build a-tools 2.0-1 -r "'a = 2.0'"


    try_install a-1.5-1 "a-1.5-1,a-tools-1.5-1" "a-1.0-1,a-tools-1.0-1"
}

testUpgradeMultipleInstalledGiveUp() {
    msgn "Preparing repositories..."
    build_installed a 0.9.8c-1
    build_installed a 1.0.0o-1
    build_installed a 1.1.1j-1

    build a 1.1.1k-1

    is_verbose_mode && $POLDEK_INSTALL -uvt a

    typeset out=$($POLDEK_INSTALL -uvt a)
    #[ $? -eq 0 ] || fail "$POLDEK_INSTALL $cmd failed"
    echo $out | grep -q 'error' || fail "unexpected success (missing 'error')"
    echo $out | grep 'error' | grep -q 'give up' || fail "unexpected success (missing 'give up')"
}


testUpgradeMultipleInstalled() {
    msgn "Preparing repositories..."
    build_installed a 0.9.8c-1
    build_installed a 1.0.0o-1
    build_installed a 1.1.1j-1

    build a 1.1.1k-1

    POLDEK_INSTALL="$POLDEK_INSTALL -Oupgrade_multiple_instances=y"
    try_install a "a-1.1.1k-1" "a-1.1.1j-1"
}


. ./sh/lib/shunit2
