#!/bin/sh
#
# Test mhlogin
#

if test -z "${MH_OBJ_DIR}"; then
    srcdir=`dirname "$0"`/../..
    MH_OBJ_DIR=`cd "${srcdir}" && pwd`; export MH_OBJ_DIR
fi

. "${srcdir}/test/oauth/common.sh"

check_exit '-eq 1' mhlogin -

expect_no_creds() {
    cat /dev/null > "${MHTMPDIR}/$$.expected-creds"
    cat /dev/null > "${MHTMPDIR}/oauth-test"
    chmod 600 "${MHTMPDIR}/oauth-test"
}

test_mhlogin() {
    start_fakehttp
    run_test 'eval echo code | mhlogin -saslmech xoauth2 -authservice test -user nobody@example.com' \
"Load the following URL in your browser and authorize nmh to access test:

http://127.0.0.1:${http_port}/oauth/auth?response_type=code&client_id=test-id&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=test-scope

Enter the authorization code: $1"
    check_http_req
    check_creds_private
    check_creds
}

test_mhlogin_invalid_response() {
    test_mhlogin 'mhlogin: error exchanging code for OAuth2 token
mhlogin: invalid response'
}

#
# success cases
#

# TEST
start_test 'mhlogin receives access and expiration'

expect_http_post_code

fake_json_response <<EOF
{
  "access_token": "test-access",
  "token_type": "Bearer",
  "expires_in": 3600
}
EOF

expect_creds <<EOF
access-nobody@example.com: test-access
expire-nobody@example.com:
EOF

test_mhlogin

# TEST
start_test 'mhlogin receives access and refresh'

expect_http_post_code

fake_json_response <<EOF
{
  "access_token": "test-access",
  "token_type": "Bearer"
}
EOF

expect_creds <<EOF
access-nobody@example.com: test-access
EOF

test_mhlogin

# TEST
start_test 'mhlogin receives access, expiration, and refresh'

expect_http_post_code

fake_json_response <<EOF
{
  "access_token": "test-access",
  "refresh_token": "refresh-token",
  "expires_in": 3600,
  "token_type": "Bearer"
}
EOF

expect_creds <<EOF
access-nobody@example.com: test-access
refresh-nobody@example.com: refresh-token
expire-nobody@example.com:
EOF

test_mhlogin

# TEST
start_test 'mhlogin receives refresh only'

expect_http_post_code

fake_json_response <<EOF
{
  "refresh_token": "refresh-token",
  "token_type": "Bearer"
}
EOF

expect_creds <<EOF
refresh-nobody@example.com: refresh-token
EOF

test_mhlogin

# TEST
start_test 'mhlogin receives token_type only'

expect_http_post_code

fake_json_response <<EOF
{
  "token_type": "Bearer"
}
EOF

expect_no_creds

test_mhlogin_invalid_response

# TEST
start_test 'mhlogin ignores extra bits in successful response JSON'

expect_http_post_code

fake_json_response <<EOF
{
  "access_token": "test-access",
  "refresh_token": "refresh-token",
  "extra_object": {
    "a": 1,
    "b": [1, 2, 3],
    "c": [{}, {"foo": "bar"}]
  },
  "extra_int": 1,
  "expires_in": 3600,
  "token_type": "Bearer"
}
EOF

expect_creds <<EOF
access-nobody@example.com: test-access
refresh-nobody@example.com: refresh-token
expire-nobody@example.com:
EOF

test_mhlogin

# TEST
start_test 'mhlogin multiple users'

expect_http_post_code

fake_json_response <<EOF
{
  "access_token": "user3-access",
  "refresh_token": "user3-refresh",
  "expires_in": 3600,
  "token_type": "Bearer"
}
EOF

expect_creds <<EOF
access-nobody@example.com: user1-access
refresh-nobody@example.com: user1-refresh
expire-nobody@example.com:
access-nobody2@example.com: user2-access
refresh-nobody2@example.com: user2-refresh
expire-nobody2@example.com:
access-nobody3@example.com: user3-access
refresh-nobody3@example.com: user3-refresh
expire-nobody3@example.com:
EOF

fake_creds <<EOF
access-nobody@example.com: user1-access
refresh-nobody@example.com: user1-refresh
expire-nobody@example.com: 100
access-nobody2@example.com: user2-access
refresh-nobody2@example.com: user2-refresh
expire-nobody2@example.com: 100
EOF

start_fakehttp
run_test 'eval echo code | mhlogin -saslmech xoauth2 -authservice test -user nobody3@example.com' \
         "Load the following URL in your browser and authorize nmh to access test:

http://127.0.0.1:${http_port}/oauth/auth?response_type=code&client_id=test-id&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=test-scope

Enter the authorization code: $1"
check_http_req
check_creds_private
check_creds

#
# fail cases
#

# TEST
start_test 'mhlogin user enters bad code'

expect_http_post_code

fake_http_response '400 Bad Request' <<EOF
Content-Type: application/json

{
  "error": "invalid_grant"
}
EOF

expect_no_creds

test_mhlogin 'Code rejected; try again? '

# TEST
start_test 'mhlogin response has no content-type'

expect_http_post_code

fake_http_response '200 OK' <<EOF

{
  "access_token": "test-access",
  "token_type": "Bearer",
  "expires_in": 3600
}
EOF

expect_no_creds

test_mhlogin_invalid_response

# TEST
start_test 'mhlogin JSON array'

expect_http_post_code

fake_json_response <<EOF
[]
EOF

expect_no_creds

test_mhlogin_invalid_response

# TEST
start_test 'mhlogin JSON empty object'

expect_http_post_code

fake_json_response <<EOF
{}
EOF

expect_no_creds

test_mhlogin_invalid_response

# TEST
start_test 'mhlogin empty response body'

expect_http_post_code

fake_json_response <<EOF
EOF

expect_no_creds

test_mhlogin_invalid_response

# TEST
start_test 'mhlogin gets proper error from http'

expect_http_post_code

fake_http_response '400 Bad Request' <<EOF
Content-Type: application/json

{
  "error": "invalid_request"
}
EOF

expect_no_creds

test_mhlogin 'mhlogin: error exchanging code for OAuth2 token
mhlogin: bad OAuth request; re-run with -snoop and send REDACTED output to nmh-workers'

# TEST
start_test 'mhlogin -browser'

#### Strip off the error string because it can vary, e.g.,
####   "Failed to connect to 127.0.0.1 port 64546: Connection refused", or
####   "Connection timed out after 1004 milliseconds"
echo code | mhlogin -saslmech xoauth2 -authservice test -user nobody@example.com \
                    -browser "echo \$@ > ${MHTMPDIR}/$$.browser" 2>&1 1>/dev/null | \
    sed 's/\( endpoint:\) .*/\1/' > "${MHTMPDIR}/$$.mhlogin.err"
cat > "${MHTMPDIR}/$$.mhlogin.err.expected" <<EOF
mhlogin: error exchanging code for OAuth2 token
mhlogin: error making HTTP request to OAuth2 authorization endpoint:
EOF
check "${MHTMPDIR}/$$.mhlogin.err" "${MHTMPDIR}/$$.mhlogin.err.expected"

cat > "${MHTMPDIR}/$$.browser.expected" <<EOF
http://127.0.0.1:${http_port}/oauth/auth?response_type=code&client_id=test-id&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=test-scope
EOF
check "${MHTMPDIR}/$$.browser" "${MHTMPDIR}/$$.browser.expected"

# TEST
start_test 'empty authorization code'
run_test 'eval echo '' | mhlogin -saslmech xoauth2 -authservice test -user nobody@example.com' \
         "Load the following URL in your browser and authorize nmh to access test:

http://127.0.0.1:${http_port}/oauth/auth?response_type=code&client_id=test-id&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=test-scope

Enter the authorization code: Empty code; try again? "


clean_fakehttp
finish_test

exit ${failed:-0}
