# file      : tests/submit/submit-git.testscript
# license   : MIT; see accompanying LICENSE file

.include data.testscript

# Prior to running testscript with -v for debugging purposes assign true to
# the verbosity variable in the brep/submit/submit-git.in handler script and
# uncomment the following line.
#
# test.redirects += 2>!

g = git 2>! >&2

# Create and clone the reference repository.
#
root_ref = $~/ref.git
root_ref_dir = $~/ref

clone_root_ref = cp --no-cleanup -r $root_ref ./ &ref.git/***

+mkdir --no-cleanup $root_ref
+$g -C $root_ref init --bare &ref.git/***

+$g clone $root_ref $root_ref_dir &ref/***

+cat <<EOI >=$root_ref_dir/submit.config.bash
  sections[alpha]=1/alpha
  sections[beta]=1/beta
  sections[stable]=1/testing

  owners=owners
  EOI

+$g -C $root_ref_dir add '*'
+$g -C $root_ref_dir commit -m 'Add submit.config.bash'
+$g -C $root_ref_dir push

# Create the target repository.
#
root_tgt = $~/tgt.git
root_tgt_url = "file:///$~/tgt.git"

+cp -r $root_ref $root_tgt

clone_root_tgt = cp --no-cleanup -r $root_tgt ./ &tgt.git/***

# Extract the package repository.
#
+tar -C $~ -xf $src_base/hello.tar.gz &hello.git/***

# Adjust the request manifest control value to point to the package repository.
#
prj_ctl="file://$~"
pkg_ctl="$prj_ctl/hello.git"

+sed -i -e "s%^\(control:\) .+\$%\\1 $pkg_ctl%" $data_dir/request.manifest

: args
{
  : none
  :
  $* 2>>~%EOE% != 0
  %\[.+\] \[brep:error\] \[ref \] \[brep-submit-git\]: usage: .+brep-submit-git \[<options>\] <tgt-repo> \[<ref-repo>\] <dir>%
  EOE

  : dir-only
  :
  $* dir 2>>~%EOE% != 0
    %\[.+\] \[brep:error\] \[ref dir\] \[brep-submit-git\]: usage: .+brep-submit-git \[<options>\] <tgt-repo> \[<ref-repo>\] <dir>%
    EOE

  : ref-not-exist
  :
  $* "$root_tgt_url" ref dir 2>>~%EOE% != 0
    %\[.+\] \[brep:error\] \[ref dir\] \[brep-submit-git\]: 'ref' does not exist or is not a directory%
    EOE

  : dir-not-exist
  :
  mkdir ref;
  $* "$root_tgt_url" ref dir 2>>~%EOE% != 0
    %\[.+\] \[brep:error\] \[ref dir\] \[brep-submit-git\]: 'dir' does not exist or is not a directory%
    EOE

  : slash-stripped
  :
  : Test that the trailing slash is stripped from the data directory path.
  :
  $* "$root_tgt_url" dir/ 2>>~%EOE% != 0
    %\[.+\] \[brep:error\] \[ref dir\] \[brep-submit-git\]: 'dir' does not exist or is not a directory%
    EOE
}

: success
:
{
  : ref-unknown-tgt-aquire-prj-pkg
  :
  : Test that on the first package submission the project and package names
  : ownership is successfully aquired. Authentication is enabled on both the
  : reference and target repos.
  :
  : Note that here we also test that --commiter-* options are picked up
  : properly.
  :
  {
    $clone_root_data;

    $clone_root_tgt;
    tgt_url = "file:///$~/tgt.git";

    $* --committer-name 'Commiter' --committer-email 'commiter@example.com' \
       "$tgt_url" $root_ref_dir $data_dir >>"EOO";
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO

    # Check that the ownership information and the package are commited into
    # the target repository.
    #
    $g clone "$tgt_url" &tgt/***;

    # Note that some manifest values may well wrap over several lines.
    #
    cat tgt/owners/hello/project-owner.manifest >>~%EOO%;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      %control: file:///.+%
      %.*
      EOO

    cat tgt/owners/hello/libhello/package-owner.manifest >>~%EOO%;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      %control: file:///.+%
      %.*
      EOO

    test -f tgt/1/alpha/hello/libhello-0.1.0.tar.gz;

    git -C tgt log -1 >>~%EOO%;
      %commit .+%
      %Author: User Name <user@example.org>%
      %Date: .+%

          Add libhello/0.1.0 to 1/alpha/hello
      %    %
          : 1
          archive: libhello-0.1.0.tar.gz
      %    sha256sum: .{64}%
      %    timestamp: ....-..-..T..:..:..Z%
      %    client-ip: .+%
      %    user-agent: bdep/.+%
      %.
          section: alpha
          author-name: User Name
          author-email: user@example.org
      %    control: file:///.+%
      %.*
      EOO

      git -C tgt log -1 '--pretty=format:%an %ae %cn %ce' >>:EOO
        User Name user@example.org Commiter commiter@example.com
        EOO
  }

  : ref-disabled-tgt-aquire-prj-pkg
  :
  : Test that on the first package submit the project and package names
  : ownership is successfully aquired. Authentication is disabled for the
  : reference repo.
  :
  {
    $clone_root_data;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    cat <<EOI >=ref/submit.config.bash;
      sections[alpha]=1/alpha
      sections[beta]=1/beta
      sections[stable]=1/testing

      # owners=owners
      EOI

    $g -C ref commit -am 'Disable ownership';
    $g -C ref push;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" ref $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : ref-absent-tgt-aquire-prj-pkg
  :
  : Test that on the first package submit the project and package names
  : ownership is successfully aquired. Reference repo is absent.
  :
  : Note that here we also pass the --result-url option.
  :
  {
    $clone_root_data;
    $clone_root_tgt;

    $* --result-url 'https://example.com/' "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: https://example.com/libhello/0.1.0
      reference: $checksum
      EOO
  }

  : ref-unknown-tgt-auth-prj-pkg
  :
  : Test that the project and package ownership is authenticated by the target
  : repository.
  :
  {
    $clone_root_data;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    mkdir -p tgt/owners/hello/libhello;

    cat <<"EOI" >=tgt/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    cat <<"EOI" >=tgt/owners/hello/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $pkg_ctl
      EOI

    $g -C tgt add owners;
    $g -C tgt commit -m 'Add ownership info';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : ref-auth-prj-tgt-auth-pkg
  :
  : Test that the project ownersip is authenticated by the reference
  : repository and the package ownersip is authenticated by the target
  : repository.
  :
  : Note that here we also test an author-less submission.
  :
  {
    $clone_root_data;
    sed -i -e 's%^author-.+$%%' $data_dir/request.manifest;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello;

    cat <<"EOI" >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add ownership info';
    $g -C ref push;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    mkdir -p tgt/owners/hello/libhello;

    cat <<"EOI" >=tgt/owners/hello/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $pkg_ctl
      EOI

    $g -C tgt add owners;
    $g -C tgt commit -m 'Add ownership info';
    $g -C tgt push;

    $* "file:///$~/tgt.git" ref $data_dir >>"EOO";
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO

    # Check that the author/committer names/emails are properly assigned.
    #
    $g -C tgt pull;

    git -C tgt log -1 '--pretty=format:%an %ae %cn %ce' >>:EOO
      Submission Handler noreply@example.com Submission Handler noreply@example.com
      EOO
  }

  : ref-auth-prj-pkg
  :
  : Test that the project and package ownership is authenticated by the
  : reference repository.
  :
  : Note that here we also test that the project control URL value may not be
  : an immediate "parent" of the package control URL.
  :
  {
    $clone_root_data;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello/libhello;

    cat <<"EOI" >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $regex.replace("$prj_ctl", '(.*/)[^/]*', '\1')
      EOI

    cat <<"EOI" >=ref/owners/hello/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $pkg_ctl
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add ownership info';
    $g -C ref push;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" ref $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : ref-auth-prj-tgt-aquire-pkg
  :
  : Test that the project ownersip is authenticated by the reference
  : repository and the package ownersip is aquired.
  :
  {
    $clone_root_data;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello/libhello;

    cat <<"EOI" >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add ownership info';
    $g -C ref push;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" ref $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : ref-absent-tgt-disabled
  :
  : Test the package ownership authentication when reference is unspecified and
  : the target ownership handling is disabled.
  :
  {
    $clone_root_data;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    cat <<EOI >=tgt/submit.config.bash;
      sections[alpha]=1/alpha
      sections[beta]=1/beta
      sections[stable]=1/testing

      # owners=owners
      EOI

    $g -C tgt commit -am 'Disable ownership';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : section-fallback
  :
  {
    $clone_root_data;
    sed -i -e 's%^(section:) .+$%\1 delta%' $data_dir/request.manifest;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    cat <<EOI >=tgt/submit.config.bash;
      sections[alpha]=1/alpha
      sections[beta]=1/beta
      sections[stable]=1/testing
      sections['*']=1/junk

      owners=owners
      EOI

    $g -C tgt commit -am 'Add section name fallback';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 200
      message: package submission is queued: libhello/0.1.0
      reference: $checksum
      EOO
  }

  : simulate
  :
  : Test that the simulated submission still succeeds given no control URL.
  :
  {
    +$clone_root_data_clean
    +sed -i -e 's%^control: .+$%simulate: success%' $data_dir/request.manifest

    : no-result-url
    :
    {
      $clone_data;
      $clone_root_tgt;

      $* "file:///$~/tgt.git" $data_dir >>"EOO"
        : 1
        status: 200
        message: package submission is queued: libhello/0.1.0
        reference: $checksum
        EOO
    }

    : result-url
    :
    {
      $clone_data;
      $clone_root_tgt;

      $* --result-url 'https://example.com' "file:///$~/tgt.git" $data_dir >>"EOO"
        : 1
        status: 200
        message: package submission is queued: https://example.com/libhello/0.1.0
        reference: $checksum
        EOO
    }
  }
}

: failure
:
{
  : no-author
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^author-.+$%%' $data_dir/request.manifest;

    $clone_root_tgt;
    tgt_url = "file:///$~/tgt.git";

    $* "$tgt_url" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 400
      message: author-name manifest value expected
      reference: $checksum
      EOO
  }

  : no-author-email
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^author-email.+$%%' $data_dir/request.manifest;

    $clone_root_tgt;
    tgt_url = "file:///$~/tgt.git";

    $* "$tgt_url" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 400
      message: author-email manifest value expected
      reference: $checksum
      EOO
  }

  : no-author-name
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^author-name.+$%%' $data_dir/request.manifest;

    $clone_root_tgt;
    tgt_url = "file:///$~/tgt.git";

    $* "$tgt_url" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 400
      message: author-name manifest value expected
      reference: $checksum
      EOO
  }

  : ref-dup-pkg
  :
  : Test the duplicate submission due presence of the package archive in the
  : reference repo.
  :
  {
    $clone_root_data_clean;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/1/alpha/hello;
    cp $data_dir/libhello-0.1.0.tar.gz ref/1/alpha/hello/;

    $g -C ref add 1/;
    $g -C ref commit -m 'Add libhello-0.1.0.tar.gz';
    $g -C ref push;

    $* "$root_tgt_url" $~/ref $data_dir >>"EOO"
      : 1
      status: 422
      message: duplicate submission
      reference: $checksum
      EOO
  }

  : ref-used-pkg
  :
  : Test the package ownership authentication failure using the reference
  : repo. The package name is already used in other project.
  :
  {
    $clone_root_data_clean;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hi/libhello;

    cat <<"EOI" >=ref/owners/hi/project-owner.manifest;
      : 1
      name: hi
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    cat <<"EOI" >=ref/owners/hi/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/foo
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add ownership info';
    $g -C ref push;

    $* "$root_tgt_url" $~/ref $data_dir >>"EOO"
      : 1
      status: 401
      message: package owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-auth-prj
  :
  : Test the project ownership authentication failure using the reference
  : repo.
  :
  {
    $clone_root_data_clean;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello;
    cat <<EOI >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: https://example.com/foo
      EOI

    $g -C ref add owners/hello/project-owner.manifest;
    $g -C ref commit -m 'Add project ownership info';
    $g -C ref push;

    $* "$root_tgt_url" $~/ref $data_dir >>"EOO"
      : 1
      status: 401
      message: project owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-auth-pkg
  :
  : Test the package ownership authentication failure using the reference
  : repo.
  :
  {
    $clone_root_data_clean;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello/libhello;

    cat <<"EOI" >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    cat <<"EOI" >=ref/owners/hello/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/foo
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add ownership info';
    $g -C ref push;

    $* "$root_tgt_url" $~/ref $data_dir >>"EOO"
      : 1
      status: 401
      message: package owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-absent-tgt-dup-pkg
  :
  : Test the duplicate submission due presence of the package archive in the
  : target repo.
  :
  {
    $clone_root_data_clean;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    mkdir -p tgt/1/alpha/hello;
    cp $data_dir/libhello-0.1.0.tar.gz tgt/1/alpha/hello/;

    $g -C tgt add 1/;
    $g -C tgt commit -m 'Add libhello-0.1.0.tar.gz';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 422
      message: duplicate submission
      reference: $checksum
      EOO
  }

  : ref-absent-tgt-auth-pkg
  :
  : Test the package ownership authentication failure using the target repo.
  :
  {
    $clone_root_data_clean;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    mkdir -p tgt/owners/hello/libhello;

    cat <<"EOI" >=tgt/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    cat <<"EOI" >=tgt/owners/hello/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/foo
      EOI

    $g -C tgt add owners;
    $g -C tgt commit -m 'Add ownership info';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 401
      message: package owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-unknown-tgt-disabled
  :
  : Test the project ownership authentication failure when no project
  : ownership information is present in the reference and the target ownership
  : handling is disabled.
  :
  {
    $clone_root_data_clean;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    cat <<EOI >=tgt/submit.config.bash;
      sections[alpha]=1/alpha
      sections[beta]=1/beta
      sections[stable]=1/testing

      # owners=owners
      EOI

    $g -C tgt commit -am 'Disable ownership';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 401
      message: project owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-prj-tgt-disabled
  :
  : Test the project ownership authentication failure when no package
  : ownership information is present in the reference and the target ownership
  : handling is disabled.
  :
  {
    $clone_root_data_clean;

    $clone_root_ref;
    $g clone ref.git &ref/***;

    mkdir -p ref/owners/hello/libhello;

    cat <<"EOI" >=ref/owners/hello/project-owner.manifest;
      : 1
      name: hello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    $g -C ref add owners;
    $g -C ref commit -m 'Add project ownership info';
    $g -C ref push;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    cat <<EOI >=tgt/submit.config.bash;
      sections[alpha]=1/alpha
      sections[beta]=1/beta
      sections[stable]=1/testing

      # owners=owners
      EOI

    $g -C tgt commit -am 'Disable ownership';
    $g -C tgt push;

    $* "file:///$~/tgt.git" ref $data_dir >>"EOO"
      : 1
      status: 401
      message: package owner authentication failed
      reference: $checksum
      EOO
  }

  : ref-absent-tgt-used-pkg
  :
  : Test the package ownership authentication failure using the target repo.
  : The package name is already used in other project.
  :
  {
    $clone_root_data_clean;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    mkdir -p tgt/owners/hi/libhello;

    cat <<"EOI" >=tgt/owners/hi/project-owner.manifest;
      : 1
      name: hi
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/
      EOI

    cat <<"EOI" >=tgt/owners/hi/libhello/package-owner.manifest;
      : 1
      name: libhello
      author-name: User Name
      author-email: user@example.org
      control: $prj_ctl/foo
      EOI

    $g -C tgt add owners;
    $g -C tgt commit -m 'Add ownership info';
    $g -C tgt push;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 401
      message: package owner authentication failed
      reference: $checksum
      EOO
  }

  : authorization
  :
  : Test the package submission authorization failure due to the archive
  : abbreviated checksum mismatch.
  :
  {
    $clone_root_data_clean;

    sed -i -e 's%^(sha256sum:) .+$%\1 59941e842667%' \
        $data_dir/request.manifest;

    $clone_root_tgt;
    $g clone tgt.git &tgt/***;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 401
      message: package publishing authorization failed
      reference: $checksum
      EOO
  }

  : section-unknown
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^(section:) .+$%\1 delta%' $data_dir/request.manifest;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" $root_ref_dir $data_dir >>"EOO"
      : 1
      status: 400
      message: unrecognized section 'delta'
      reference: $checksum
      EOO
  }

  : control-unavailable
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^(control:) .+$%\1 http://non-existent-host/path/rep.git%' \
        $data_dir/request.manifest;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 422
      message: repository http://non-existent-host/path/rep.git unavailable
      reference: $checksum
      EOO
  }

  : control-clone-failed
  :
  {
    $clone_root_data_clean;
    sed -i -e 's%^(control:) .+$%\1 http://example.com/path/rep.git%' \
        $data_dir/request.manifest;

    $clone_root_tgt;

    $* "file:///$~/tgt.git" $data_dir >>"EOO"
      : 1
      status: 422
      message: failed to git-clone http://example.com/path/rep.git
      reference: $checksum
      EOO
  }

  : target-unavailable
  :
  {
    $clone_root_data_clean;

    $* 'http://non-existent-host/path/rep.git' $data_dir >>"EOO" 2>>~%EOE%
      : 1
      status: 503
      message: submission service temporarily unavailable
      reference: $checksum
      EOO
      %curl: .+%
      EOE
  }

  : target-clone-failed
  :
  {
    $clone_root_data_clean;

    $* 'http://example.com/path/rep.git' $data_dir 2>>~%EOE% != 0
      %fatal: .+%
      EOE
  }
}