-- This program only works in an environment that has installed the Openresty
-- profiling tools using the scripts under /script/install.

local function capture_output(command)
  local f = assert(io.popen(command))

  local out = {}

  for line in f:lines() do
    table.insert(out, line)
  end

  f:close()

  return table.concat(out, '\n')
end

local function pid_from_file(pid_file)
  return capture_output("cat " .. pid_file)
end

local Profiler = {}
do
  function Profiler.check_trace_exits(pid, duration)
    local trace_exits_command = string.format(
      'PATH="$PATH:/usr/local/bin" /usr/local/bin/ngx-lj-trace-exits.sxx -x %s --arg time=%s',
      pid, duration
    )

    local output = capture_output(trace_exits_command)
    print(output)

    local jitted, total = string.match(
      output,
      '(%d+) out of (%d+) requests used compiled traces generated by LuaJIT.'
    )

    local perc_using_traces = (jitted/total)*100

    if perc_using_traces < 95 then
      return false, 'only ' .. perc_using_traces .. '% of the requests used LuaJIT traces.'
    else
      return true
    end
  end
end

local Wrk = {
  make_requests = function(duration)
    local command = string.format('wrk --connections 10 --threads 10 --duration %s http://localhost:8080 &', duration)
    os.execute(command)
  end
}

local APIcast = { }
do
  local apicast_bin = 'bin/apicast'

  function APIcast.start_with_config_file(config_file, pid_file)
    local command = string.format(
      'APICAST_WORKERS=1 THREESCALE_CONFIG_FILE=%s %s --daemon --pid %s',
      config_file,
      apicast_bin,
      pid_file
    )
    os.execute(command)
  end

  function APIcast.start_with_env_file(env_file, pid_file)
    local command = string.format(
      'APICAST_WORKERS=1 APICAST_ENVIRONMENT=%s %s --daemon --pid %s',
      env_file,
      apicast_bin,
      pid_file
    )
    os.execute(command)
  end
end

-- The simple scenario consists of two APIcasts. One of them is just used as an
-- echo API. The other is the one that is profiled, its configuration is very
-- simple. It has one service with the Upstream policy configured to match any
-- request path and select the echo API of the other APIcast as the upstream.
-- With this we can profile APIcast with a minimal configuration proxying
-- requests and isolating the possible effects of generating an "echo"
-- response.
local SimpleScenario = { }
do
  local echo_apicast = {
    pid_file = '/tmp/echo_apicast.pid',
    env_file = 'script/profiling/configs/echo_config.lua'
  }

  local profile_apicast = {
    pid_file = '/tmp/apicast.pid',
    config_file = 'script/profiling/configs/profile_apicast_config.json'
  }

  local function start_echo_apicast()
    APIcast.start_with_env_file(echo_apicast.env_file, echo_apicast.pid_file)
  end

  local function start_apicast_to_profile()
    APIcast.start_with_config_file(profile_apicast.config_file, profile_apicast.pid_file)
  end

  -- Returns the PID of the worker of the APIcast to profile
  function SimpleScenario.setup()
    start_echo_apicast()
    start_apicast_to_profile()

    local master_pid = pid_from_file(profile_apicast.pid_file)
    return capture_output('pgrep --parent ' .. master_pid)
  end

  function SimpleScenario.teardown()
    local pids = {
      pid_from_file(profile_apicast.pid_file),
      pid_from_file(echo_apicast.pid_file)
    }

    for _, pid in ipairs(pids) do
      os.execute('kill ' .. pid)
    end
  end
end


local duration = 30
local pid_to_profile = SimpleScenario.setup()
Wrk.make_requests(duration)
local ok, err_msg = Profiler.check_trace_exits(pid_to_profile, duration)
SimpleScenario.teardown()

if not ok then
  error(err_msg)
end
