# Copyright 2020 The IREE Authors
#
# Licensed under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

# Wrapper script to push build artifacts and run tests on an Android device.
#
# This script expects the following arguments:
#   <test-binary> [<test-args>]..
# Where <test-binary> should be a path relative to /data/local/tmp/ on device.
#
# This script reads the following environment variables:
# - TEST_ANDROID_ABS_DIR: the absolute path on Android device for the build
#   artifacts.
# - TEST_DATA: optional; the data file to push to the Android device.
# - TEST_EXECUTABLE: the executable file to push to the Android device.
# - TEST_TMPDIR: optional; temporary directory on the Android device for
#   running tests.
#
# This script pushes $env:TEST_EXECUTABLE and $env:TEST_DATA onto the device
# under $env:TEST_ANDROID_ABS_DIR/ before running <test-binary> with all
# <test-args> under /data/local/tmp.

param(
  [Parameter(Position=0, Mandatory)]
  [ValidateNotNullOrEmpty()]
  [string]
    $test_binary,
  [Parameter(Position=1, ValueFromRemainingArguments=$true)]
  [string[]]
    $test_args = @()
)

# NOTE: to debug first run `$DebugPreference = 'Continue'` in your shell.
# $DebugPreference = "Continue"

# Composes arguments for adb to push `$data` to `$dest` on device.
function Compose-AdbPushCommand {
  param([string]$data, [string]$dest)

  $filename = Split-Path $data -leaf
  $adb_params = "push", $data, "$dest/$filename"
  $adb_params = $adb_params -join " "

  return $adb_params
}

# Composes arguments for adb to run the given `$adb_cmd` and returns a string:
#   shell "cd /data/local/tmp && $adb_cmd"
function Compose-AdbShellCommand {
  param([string[]]$adb_cmd)

  $adb_cmd_prefix = "cd", "/data/local/tmp", "&&"
  $adb_params = $adb_cmd_prefix + $adb_cmd
  $adb_params = $adb_params -join " "
  $adb_params = ('"', $adb_params, '"') -join ""

  $adb_params = "shell " + $adb_params
  Write-Host -ForegroundColor Yellow "adb parameters: $adb_params"
  return $adb_params
}

# Invokes adb at `$adb_path` with the given parameters `$adb_params`.
function Invoke-Adb {
  param([string]$adb_path, [string]$adb_params)

  $process = Start-Process -FilePath $adb_path -ArgumentList $adb_params -NoNewWindow -PassThru
  # HACK: Start-Process is broken... wow.
  # https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
  $handle = $process.Handle
  $exitcode = 1
  $timeout_millis = 120 * 1000
  if ($process.WaitForExit($timeout_millis) -eq $false) {
    Write-Error "adb timed out after $timeout_millis millis"
  } else {
    $exitcode = $process.ExitCode
    Write-Debug "adb returned in time with exit code $($exitcode)"
  }

  if ($process.ExitCode -ne 0) {
    Write-Debug "adb exited with $exitcode"
    exit $exitcode
  }
}

Write-Host -ForegroundColor Yellow "Requested adb command: $test_binary $test_args"

$adb_path = $(Get-Command adb -Type Application).Path
Write-Host -ForegroundColor Yellow "Using adb executable: $adb_path"

# Push the artifacts needed for testing to Android device.
$adb_push_exe_params = Compose-AdbPushCommand $env:TEST_EXECUTABLE $env:TEST_ANDROID_ABS_DIR
Invoke-Adb $adb_path $adb_push_exe_params
if ($env:TEST_DATA -ne $null) {
  $adb_push_data_params = Compose-AdbPushCommand $env:TEST_DATA $env:TEST_ANDROID_ABS_DIR
  Invoke-Adb $adb_path $adb_push_data_params
}

$exe_name = Split-Path $env:TEST_EXECUTABLE -leaf
$adb_mark_executable_params = Compose-AdbShellCommand "chmod","+x",$env:TEST_ANDROID_ABS_DIR/$exe_name
Invoke-Adb $adb_path $adb_mark_executable_params

if ($env:TEST_TMPDIR -ne $null) {
  $adb_mkdir_params = Compose-AdbShellCommand "mkdir","-p",$env:TEST_TMPDIR
  Invoke-Adb $adb_path $adb_mkdir_params
  $tmpdir = "TEST_TMPDIR=" + $env:TEST_TMPDIR
} else {
  $tmpdir = ""
}

# We set LD_LIBRARY_PATH for the command so that it can use libvulkan.so under
# /data/local/tmp when running Vulkan tests. This is to workaround an Android
# issue where linking to libvulkan.so is broken under /data/local/tmp.
# See https://android.googlesource.com/platform/system/linkerconfig/+/296da5b1eb88a3527ee76352c2d987f82f3252eb.
# This requires copying the vendor vulkan implementation under
# /vendor/lib[64]/hw/vulkan.*.so to /data/local/tmp/libvulkan.so.
$adb_shell_params = Compose-AdbShellCommand "LD_LIBRARY_PATH=/data/local/tmp",$tmpdir,$test_binary,$test_args
Invoke-Adb $adb_path $adb_shell_params

if ($env:TEST_TMPDIR -ne $null) {
  $adb_rm_params = Compose-AdbShellCommand "rm","-rf",$env:TEST_TMPDIR
  Invoke-Adb $adb_path $adb_rm_params
}

exit 0
