#!/usr/bin/env bash
set -euo pipefail

# message: Prints a message to the console with a timestamp and prefix.
message() {
  local msg="$1"
  printf "\n> %s - %s\n" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$msg"
}

# run: Runs the tool and fails early if it fails.
run() {
  local cmd="$1"
  message "Running: $cmd"
  if ! eval "$cmd"; then
    message "Command failed: $cmd"
    exit 1
  fi
  message "Command ran successfully: $cmd"
}

contrib=""
sleeptime=10
unset INTEGRATION
unset DD_APPSEC_ENABLED

if [[ "$(uname -s)" = 'Darwin' && "$(uname -m)" = 'arm64' ]]; then
  # Needed to run integration tests on Apple Silicon
  export DOCKER_DEFAULT_PLATFORM=linux/amd64
fi

while [[ $# -gt 0 ]]; do
  case $1 in
    -a | --appsec)
      export DD_APPSEC_ENABLED=true
      shift
      ;;
    -i | --integration)
      export INTEGRATION=true
      shift
      ;;
    -c | --contrib)
      contrib=true
      shift
      ;;
    --all)
      contrib=true
      export DD_APPSEC_ENABLED=true
      export DD_TEST_APPS_ENABLED=true
      export INTEGRATION=true
      shift
      ;;
    -s | --sleep)
      sleeptime=$2
      shift
      shift
      ;;
    -h | --help)
      echo "test.sh - Run the tests for dd-trace-go"
      echo "  this script requires gotestsum, goimports, docker and docker-compose."
      echo "  -a | --appsec      - Test with appsec enabled"
      echo "  -i | --integration - Run integration tests. This requires docker and docker-compose. Resource usage is significant when combined with --contrib"
      echo "  -c | --contrib     - Run contrib tests"
      echo "  --all              - Synonym for -l -a -i -c"
      echo "  -s | --sleep       - The amount of seconds to wait for docker containers to be ready - default: 30 seconds"
      echo "  -t | --tools       - Install gotestsum and goimports"
      echo "  -h | --help        - Print this help message"
      exit 0
      ;;
    *)
      echo "Ignoring unknown argument $1"
      shift
      ;;
  esac
done

if [[ "$INTEGRATION" != "" ]]; then
  ## Make sure we shut down the docker containers on exit.
  function finish {
    message "Cleaning up..."
    docker compose down
  }
  trap finish EXIT
  if [[ "$contrib" != "" ]]; then
    ## Start these now so they'll be ready by the time we run integration tests.
    docker compose up -d
  else
    ## If we're not testing contrib, we only need the trace agent.
    docker compose up -d datadog-agent
  fi
fi

## CORE
message "Testing core..."
mapfile -t pkg_names < <(go list ./...)
nice -n20 gotestsum --junitfile ./gotestsum-report.xml -- -race -v -coverprofile=core_coverage.txt -covermode=atomic "${pkg_names[@]}" && true

if [[ "$contrib" != "" ]]; then
  ## CONTRIB
  message "Testing contrib..."

  if [[ "$INTEGRATION" != "" ]]; then
    ## wait for all the docker containers to be "ready"
    message "Waiting for docker for ${sleeptime} seconds"
    sleep "${sleeptime}"
  fi

  find . -mindepth 2 -type f -name go.mod | while read -r go_mod_path; do
    dir=$(dirname "$go_mod_path")
    [ "$dir" = "./tools/v2fix/_stage" ] && continue
    [ "$dir" = "./scripts/autoreleasetagger/testdata/root" ] && continue
    [ "$dir" = "./scripts/autoreleasetagger/testdata/root/moduleA" ] && continue
    [ "$dir" = "./scripts/autoreleasetagger/testdata/root/moduleB" ] && continue

    cd "$dir"
    message "Testing $dir"
    mapfile -t pkgs < <(go list ./... | grep -v -e google.golang.org/api)
    if [[ ${#pkgs[@]} -eq 0 ]]; then
      cd - > /dev/null
      continue
    fi
    pkg_id="${pkgs[0]#github.com/DataDog/dd-trace-go/v2}"
    pkg_id="${pkg_id//\//_}"
    nice -n20 gotestsum --junitfile "./gotestsum-report.$pkg_id.xml" -- -race -v -coverprofile="contrib_coverage.$pkg_id.txt" -covermode=atomic "${pkgs[@]}"
    cd - > /dev/null
  done
fi
