Skip to content

Lookup load

Lookup Load Test Script for wrkยถ

lookup_load.lua
-- === CONFIG ===
local NUM_MSISDNS = 30000
local BASE_URL = "https://api.il.unibeam.com"
local CALLBACK_URL = "https://roiwebhook.unibeam.us/callback"
local CUSTOMER_ID = "roi"
local AUTH_USERNAME = "unibeam"
local AUTH_PASSWORD = "abcd1234"
local MESSAGE = "hello7"

-- === TOKEN CONFIG ===
local token_expiration_minutes = 60
local token_valid_for = token_expiration_minutes * 60
local token_fetched_at = 0
local token = nil
local authenticated = false

-- === GLOBALS ===
local msisdn_index = 1
local api_paths = {
  "/api/v1/lookup"
}
local threads = {}

-- === UTILS ===
local function uuid()
  local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
  return string.gsub(template, "[xy]", function(c)
    local v = (c == "x") and math.random(0, 15) or math.random(8, 11)
    return string.format("%x", v)
  end)
end

-- === MSISDN LIST ===
local msisdns = (function()
  local list = {}
  for i = 1, NUM_MSISDNS do
    list[i] = tostring(i)
  end
  return list
end)()

-- === SETUP ===
function setup(thread)
  table.insert(threads, thread)
  local threadId = tonumber(tostring(thread):match("0x%x+")) or 0
  math.randomseed(os.time() + threadId)
  local offset = math.random(0, NUM_MSISDNS)
  thread:set("offset", offset)
  thread:set("status_not_found", 0)
end

-- === REQUEST ===
function request()
  local now = os.time()
  local token_expired = (not token_fetched_at) or (now - token_fetched_at >= token_valid_for)

  if not authenticated or token_expired then
    authenticated = false
    token = nil
    local body = string.format('{"username":"%s","password":"%s"}', AUTH_USERNAME, AUTH_PASSWORD)
    return wrk.format("POST", "/authenticate", {
      ["Content-Type"] = "application/json",
      ["customerId"] = CUSTOMER_ID
    }, body)
  end

  -- MSISDN & API rotation logic
  local offset = wrk.thread:get("offset") or 0
  local index = ((msisdn_index + offset - 1) % NUM_MSISDNS) + 1
  local msisdn = msisdns[index]
  local api_index = ((msisdn_index - 1) % #api_paths) + 1
  local path = api_paths[api_index]
  local reqId = uuid()

  local body = ""
  if api_index == 1 then
    body = string.format([[{
      "msisdn":"%s",
      "cbUrl":"%s",
      "requestId":"%s",
      "message":"%s",
      "rejectOnActiveCall":false
    }]], msisdn, CALLBACK_URL, reqId, MESSAGE)

  elseif api_index == 2 then
    body = string.format([[{
      "msisdn":"%s",
      "cbUrl":"%s",
      "requestId":"%s",
      "message":"%s"
    }]], msisdn, CALLBACK_URL, reqId, MESSAGE)

  elseif api_index == 3 then
    body = string.format([[{
      "msisdn":"%s",
      "cbUrl":"%s",
      "requestId":"%s"
    }]], msisdn, CALLBACK_URL, reqId)
  end

  -- Increment index
  msisdn_index = msisdn_index + 1
  if msisdn_index > NUM_MSISDNS then msisdn_index = 1 end

  return wrk.format("POST", path, {
    ["Content-Type"] = "application/json",
    ["customerId"] = CUSTOMER_ID,
    ["Authorization"] = "Bearer " .. token
  }, body)
end

-- === RESPONSE ===
function response(status, headers, body)
  if body then local _ = body:sub(1, 1) end

  if not authenticated and status == 200 and body then
    token = body:match('"token"%s*:%s*"([^"]+)"')
    if token then
      authenticated = true
      token_fetched_at = os.time()
    end
  end

  -- Count status codes
  local key = "status_" .. tostring(status)
  local count = wrk.thread:get(key) or 0
  wrk.thread:set(key, count + 1)

  -- Look for "status":"NOT_FOUND" in JSON body
  if status == 200 and body and body:match('"status"%s*:%s*"NOT_FOUND"') then
    local nf = wrk.thread:get("status_not_found") or 0
    wrk.thread:set("status_not_found", nf + 1)
  end
end

-- === DONE ===
function done(summary, latency, requests)
  local status_counts = {
    ["200"] = 0,
    ["400"] = 0,
    ["401"] = 0,
    ["403"] = 0,
    ["500"] = 0
  }
  local other = 0

  for _, thread in ipairs(threads) do
    for _, code in ipairs({"200", "400", "401", "403", "500"}) do
      local key = "status_" .. code
      local count = thread:get(key) or 0
      status_counts[code] = status_counts[code] + count
    end

    for i = 100, 599 do
      local code = tostring(i)
      if not status_counts[code] then
        local key = "status_" .. code
        local count = thread:get(key)
        if count then other = other + count end
      end
    end
  end

  print("------------------------------")
  print("๐Ÿ“Š Response Code Breakdown:")
  for _, code in ipairs({"200", "400", "401", "403", "500"}) do
    print(string.format("%s: %d", code, status_counts[code]))
  end
  local not_found_total = 0
    for _, thread in ipairs(threads) do
      local nf = thread:get("status_not_found") or 0
      not_found_total = not_found_total + nf
    end

  print(string.format("โ“ NOT_FOUND in response body: %d", not_found_total))
  print(string.format("Other: %d", other))
  print("๐Ÿ“ฆ Total requests: " .. summary.requests)
  print("------------------------------")
end