#!/bin/sh
# $Id$

. ./sh/lib/setup
. ./sh/lib/repo-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 $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

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


PACKAGE_DIR="$REPO"
DEFAULT_VER="1-1"

do_build_package() {
  destdir=$1; shift
  name=$1; shift
  version=""


  [ $# -gt 0 ] && version="$1";
  #echo "v $version"
  if [ -n "$version" ]; then 
      if echo "$version" | egrep -qv -- '^-'; then
          shift
      else
          version="1-1"
      fi    
  fi
  [ -n "$version" ] || version="1-1"
  
  params=""
  [ $# -gt 0 ] && params="$@";  
  if [ "$VERBOSE" != "-v -v" ]; then
      eval ./build-test-rpm.sh -d $destdir -n $name -v $version $params >/dev/null 2>&1 || fail "build package $name failed"
  else    
      eval ./build-test-rpm.sh -d $destdir -n $name -v $version $params
      [ $? -eq 0 ] || fail "build package $name failed"
  fi

} 

build() {
   do_build_package $REPO $@
}

build2() {
   do_build_package $REPO2 $@
}

build_installed() {
   do_build_package $DESTINATION_REPO $@
}

runpoldek() {
  typeset cmd="$POLDEK_INSTALL $@"
  if is_verbose_mode; then
      echo "Executing $cmd"
      $cmd || fail "'poldek $@' failed"
  else
      $cmd >/dev/null 2>&1 || fail "'poldek $@' failed"
  fi
}
 
# try to install package and check result
# usage: try_install <package> <expected installed> [<expected removed>]
try_install() {
  typeset package="$1"; shift  
  typeset expected="$1"; shift
  typeset rm_expected=""
  if [ $# -gt 0 ]; then
      rm_expected="$1"
      shift
  fi

  typeset regexp=$(echo $expected | sed 's/,/|/g')
  typeset n_expected=$(echo $expected | sed 's|,|\n|g' | wc -l)
  if [ -n "$rm_expected" ]; then
      typeset rm_regexp=$(echo $rm_expected | sed 's/,/|/g')
      typeset rm_n_expected=$(echo $rm_expected | sed 's|,|\n|g' | wc -l)
  fi

  typeset cmd="-uvt $package"
  if [ $# -gt 0 ]; then
      cmd="$1 $cmd"
      shift
  fi
  runpoldek $cmd  

  typeset out=$($POLDEK_INSTALL $cmd --parsable-tr-summary | egrep "^%[IDR]")

  typeset n_all=$(echo $out | sed 's|%|\n%|g' | egrep '^%[ID]' | wc -l)
  typeset n=$(echo $out | sed 's|%|\n%|g' | egrep "^%[ID] ($regexp)" | wc -l)
  assertEquals "unexpected ($n_all) number of packages (expected $n)" "$n_all" "$n"
  assertEquals "not all or non expected packages installed (expected $expected)" "$n" "$n_expected"

  if [ -n "$rm_expected" ]; then   
      typeset n_all=$(echo $out | sed 's|%|\n%|g' | egrep '^%R' | wc -l)
      typeset n=$(echo  $out | sed 's|%|\n%|g' | egrep "^%R ($rm_regexp)" | wc -l)
      assertEquals "unexpected ($n_all) number of packages removed (expected $n)" "$n_all" "$n"
      assertEquals "not all or non expected packages removed (expected $rm_expected)" "$n" "$rm_n_expected"
  fi
}

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"  
}

# 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"
}

# suggested packages should be installed 
testSuggests() {
    build_installed suggested
    build a -s "suggested" -s "b" -s "c"
    build b
    build c
    POLDEK_TESTING_WITH_SUGGESTS="all" # choose all suggested packages
    export POLDEK_TESTING_WITH_SUGGESTS
    try_install_a "a,b,c" 

    POLDEK_TESTING_WITH_SUGGESTS="2" # choose b only (1st installable suggested package)
    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 $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"
}


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
       echo "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
    try_install n "n-1-1.noarch,a-1-1.i686"
    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"
}

testMultilibNoSuccesor() {
    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
       echo "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"
}


# NFY should score orphan successors
testOrhpanSuccessorScore() {
    #ORIG_POLDEK_INSTALL="$POLDEK_INSTALL"
    #POLDEK_INSTALL="$POLDEK_INSTALL -Omultilib=1"

    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"
    #POLDEK_INSTALL="$ORIG_POLDEK_INSTALL"
}


. ./sh/lib/shunit2