go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/quota/internal/luatest/testdata/test_fixtures.lua (about)

     1  -- Copyright 2022 The LUCI Authors
     2  --
     3  -- Licensed under the Apache License, Version 2.0 (the "License");
     4  -- you may not use this file except in compliance with the License.
     5  -- You may obtain a copy of the License at
     6  --
     7  --      http://www.apache.org/licenses/LICENSE-2.0
     8  --
     9  -- Unless required by applicable law or agreed to in writing, software
    10  -- distributed under the License is distributed on an "AS IS" BASIS,
    11  -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  -- See the License for the specific language governing permissions and
    13  -- limitations under the License.
    14  
    15  lu = require 'luaunit/luaunit'
    16  -- This makes tracebacks work correctly; otherwise they show the location inside
    17  -- of the luaunit assertion function. Suspect something to do with Go lua impl.
    18  lu.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE = 1
    19  
    20  
    21  function dumpTable(table, depth)
    22    if depth == nil then
    23      depth = 0
    24    end
    25    if (depth > 200) then
    26      print("Error: Depth > 200 in dumpTable()")
    27      return
    28    end
    29    for k,v in pairs(table) do
    30      if (type(v) == "table") then
    31        print(string.rep("  ", depth)..k..":")
    32        dumpTable(v, depth+1)
    33      else
    34        print(string.rep("  ", depth)..k..": ",v)
    35      end
    36    end
    37  end
    38  
    39  KEYS = {"account_key~account_name", "policy_key"}
    40  
    41  cmsgpack = require 'luamsgpack/MessagePack'
    42  
    43  PB = loadfile('../../../quotapb/quotapb.lua')()
    44  
    45  T0_SEC = 1670834486
    46  T0_MSEC = 0
    47  
    48  function DUMP(...)
    49    local toprint = {}
    50    for i, v in next, arg do
    51      if type(v) == "table" then
    52        v = cjson.encode(v)
    53      end
    54      toprint[i] = v
    55    end
    56    print(unpack(toprint))
    57  end
    58  
    59  redis = {
    60    DATA = {},
    61    TTL = {}
    62  }
    63  
    64  function redis.call(method, ...)
    65    local function check(nameTypes)
    66      if #nameTypes ~= arg.n then
    67        error(string.format("TEST ERROR: redis:call: %s: wrong arg.n: %d != %d", method, #nameTypes, args.n))
    68      end
    69      for i, nameType in ipairs(nameTypes) do
    70        local t = type(arg[i])
    71        local name, want = unpack(nameType)
    72        if t ~= want then
    73          error(string.format("TEST ERROR: redis:call: %s: bad %s type: %s, wanted %s", method, name, t, want))
    74        end
    75      end
    76      return unpack(arg)
    77    end
    78  
    79    if method == "HGET" then
    80      local key, field = check({{"key", "string"}, {"field", "string"}})
    81      return (redis.DATA[key] or {})[field]
    82    end
    83  
    84    if method == "HMGET" then
    85      local key, field, field2, field3 = check({
    86        {"key", "string"},
    87        {"field", "string"},
    88        {"field2", "string"},
    89        {"field3", "string"},
    90      })
    91      local subCache = (redis.DATA[key] or {})
    92      return {subCache[field], subCache[field2], subCache[field3]}
    93    end
    94  
    95    if method == "HSET" and arg.n == 3 then
    96      local key, field, value = check({
    97        {"key", "string"},
    98        {"field", "string"}, {"value", "string"},
    99      })
   100      local subCache = redis.DATA[key]
   101      if subCache == nil then
   102        subCache = {}
   103        redis.DATA[key] = subCache
   104      end
   105      subCache[field] = tostring(value)
   106      return
   107    end
   108  
   109    if method == "HSET" and arg.n == 5 then
   110      local key, field, value, field2, value2 = check({
   111        {"key", "string"},
   112        {"field", "string"}, {"value", "string"},
   113        {"field2", "string"}, {"value2", "string"},
   114      })
   115      local subCache = redis.DATA[key]
   116      if subCache == nil then
   117        subCache = {}
   118        redis.DATA[key] = subCache
   119      end
   120      subCache[field] = tostring(value)
   121      subCache[field2] = tostring(value3)
   122      return
   123    end
   124  
   125    if method == "HSET" then
   126      local key, field, value, field2, value2, field3, value3 = check({
   127        {"key", "string"},
   128        {"field", "string"}, {"value", "string"},
   129        {"field2", "string"}, {"value2", "string"},
   130        {"field3", "string"}, {"value3", "string"},
   131      })
   132      local subCache = redis.DATA[key]
   133      if subCache == nil then
   134        subCache = {}
   135        redis.DATA[key] = subCache
   136      end
   137      subCache[field] = tostring(value)
   138      subCache[field2] = tostring(value2)
   139      subCache[field3] = tostring(value3)
   140      return
   141    end
   142  
   143    if method == "GET" then
   144      local key = check({{"key", "string"}})
   145      return redis.DATA[key]
   146    end
   147  
   148    if method == "SET" and arg.n == 4 then
   149      local key, value, PX, TTL = check({
   150        {"key", "string"}, {"value", "string"},
   151        {"PX", "string"}, {"TTL", "number"},
   152      })
   153      if PX ~= "PX" then
   154        error(string.format("TEST ERROR: unexpected option %s != PX", PX))
   155      end
   156      redis.DATA[key] = value
   157      redis.TTL[key] = TTL
   158      return
   159    end
   160  
   161    if method == "SET" then
   162      local key, value = check({{"key", "string"}, {"value", "string"}})
   163      redis.DATA[key] = value
   164      redis.TTL[key] = nil
   165      return
   166    end
   167  
   168    if method == "PEXPIRE" then
   169      local key, exp = check({{"key", "string"}, {"exp", "number"}})
   170      redis.TTL[key] = exp
   171      return
   172    end
   173  
   174    if method == "TIME" then
   175      check({})
   176      return {T0_SEC, T0_MSEC}
   177    end
   178  
   179    error(string.format("TEST ERROR: redis.call unsupported method %s", method))
   180  end
   181  
   182  function redis.error_reply(msg)
   183    return { error = "ERR "..msg }
   184  end
   185  
   186  function redis.status_reply(obj)
   187    return { ok = obj }
   188  end
   189  
   190  local Utils = loadfile('../../lua/utils.lua')(PB, policyNames)
   191  local Policy = loadfile('../../lua/policy.lua')(PB, Utils)
   192  local Account = loadfile('../../lua/account.lua')(PB, Utils, Policy)
   193  
   194  G = {}
   195  G.Utils = Utils
   196  G.Policy = Policy
   197  G.Account = Account
   198  
   199  -- This is a hack; we hook the output to reset global state.
   200  -- The alternative would be to add a layer of 'test classes', but for our
   201  -- purposes, this should be OK.
   202  local realStartTest = lu.LuaUnit.outputType.startTest
   203  lu.LuaUnit.outputType.startTest = function( self, testName )
   204    redis.DATA = {}
   205    redis.TTL = {}
   206  
   207    Policy.CACHE = {}
   208    Account.CACHE = {}
   209    Utils.NOW.seconds = T0_SEC
   210    Utils.NOW.nanos = T0_MSEC * 1000000
   211  
   212    realStartTest(self, testName)
   213  end