#!/bin/bash
#
#  Copyright 2019 gRPC authors.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

set +e -x

export TMPDIR=$(mktemp -d)
trap "rm -rf ${TMPDIR}" EXIT

clean () {
  for i in {1..10}; do
    jobs -p | xargs -n1 pkill -P
    # A simple "wait" just hangs sometimes.  Running `jobs` seems to help.
    sleep 1
    if jobs | read; then
      return
    fi
  done
  echo "$(tput setaf 1) clean failed to kill tests $(tput sgr 0)"
  jobs
  pstree
  exit 1
}

fail () {
    echo "$(tput setaf 1) $1 $(tput sgr 0)"
    clean
    exit 1
}

pass () {
    echo "$(tput setaf 2) $1 $(tput sgr 0)"
}

EXAMPLES=(
    "helloworld"
    "route_guide"
    "features/authentication"
    "features/compression"
    "features/deadline"
    "features/encryption/TLS"
    "features/errors"
    "features/interceptor"
    "features/load_balancing"
    "features/metadata"
    "features/multiplex"
    "features/name_resolving"
)

declare -A EXPECTED_SERVER_OUTPUT=(
    ["helloworld"]="Received: world"
    ["route_guide"]=""
    ["features/authentication"]="server starting on port 50051..."
    ["features/compression"]="UnaryEcho called with message \"compress\""
    ["features/deadline"]=""
    ["features/encryption/TLS"]=""
    ["features/errors"]=""
    ["features/interceptor"]="unary echoing message \"hello world\""
    ["features/load_balancing"]="serving on :50051"
    ["features/metadata"]="message:\"this is examples/metadata\" , sending echo"
    ["features/multiplex"]=":50051"
    ["features/name_resolving"]="serving on localhost:50051"
)

declare -A EXPECTED_CLIENT_OUTPUT=(
    ["helloworld"]="Greeting: Hello world"
    ["route_guide"]="location:<latitude:416851321 longitude:-742674555 >"
    ["features/authentication"]="UnaryEcho:  hello world"
    ["features/compression"]="UnaryEcho call returned \"compress\", <nil>"
    ["features/deadline"]="wanted = DeadlineExceeded, got = DeadlineExceeded"
    ["features/encryption/TLS"]="UnaryEcho:  hello world"
    ["features/errors"]="Greeting: Hello world"
    ["features/interceptor"]="UnaryEcho:  hello world"
    ["features/load_balancing"]="calling helloworld.Greeter/SayHello with pick_first"
    ["features/metadata"]="this is examples/metadata"
    ["features/multiplex"]="Greeting:  Hello multiplex"
    ["features/name_resolving"]="calling helloworld.Greeter/SayHello to \"example:///resolver.example.grpc.io\""
)

for example in ${EXAMPLES[@]}; do
    echo "$(tput setaf 4) testing: ${example} $(tput sgr 0)"

    # Build server
    if ! go build -o /dev/null ./examples/${example}/*server/*.go; then
        fail "failed to build server"
    else
        pass "successfully built server"
    fi

    # Build client
    if ! go build -o /dev/null ./examples/${example}/*client/*.go; then
        fail "failed to build client"
    else
        pass "successfully built client"
    fi

    # Start server
    SERVER_LOG="$(mktemp)"
    go run ./examples/$example/*server/*.go &> $SERVER_LOG  &

    CLIENT_LOG="$(mktemp)"
    if ! timeout 20 go run examples/${example}/*client/*.go &> $CLIENT_LOG; then
        fail "client failed to communicate with server
        got server log:
        $(cat $SERVER_LOG)
        got client log:
        $(cat $CLIENT_LOG)
        "
    else
        pass "client successfully communitcated with server"
    fi

    # Check server log for expected output if expecting an
    # output
    if [ -n "${EXPECTED_SERVER_OUTPUT[$example]}" ]; then
        if ! grep -q "${EXPECTED_SERVER_OUTPUT[$example]}" $SERVER_LOG; then
            fail "server log missing output: ${EXPECTED_SERVER_OUTPUT[$example]}
            got server log:
            $(cat $SERVER_LOG)
            got client log:
            $(cat $CLIENT_LOG)
            "
        else
            pass "server log contains expected output: ${EXPECTED_SERVER_OUTPUT[$example]}"
        fi
    fi

    # Check client log for expected output if expecting an
    # output
    if [ -n "${EXPECTED_CLIENT_OUTPUT[$example]}" ]; then
        if ! grep -q "${EXPECTED_CLIENT_OUTPUT[$example]}" $CLIENT_LOG; then
            fail "client log missing output: ${EXPECTED_CLIENT_OUTPUT[$example]}
            got server log:
            $(cat $SERVER_LOG)
            got client log:
            $(cat $CLIENT_LOG)
            "
        else
            pass "client log contains expected output: ${EXPECTED_CLIENT_OUTPUT[$example]}"
        fi
    fi

    clean
done
