gitpod/components/proxy/conf/lua-prometheus/prometheus_test.lua
2020-08-25 09:25:15 +00:00

335 lines
13 KiB
Lua

-- vim: ts=2:sw=2:sts=2:expandtab
luaunit = require('luaunit')
prometheus = require('prometheus')
-- Simple implementation of a nginx shared dictionary
local SimpleDict = {}
SimpleDict.__index = SimpleDict
function SimpleDict:set(k, v)
if not self.dict then self.dict = {} end
self.dict[k] = v
return true, nil, false -- success, err, forcible
end
function SimpleDict:safe_set(k, v)
if k:find("willnotfit") then
return nil, "no memory"
end
self:set(k, v)
return true, nil -- ok, err
end
function SimpleDict:incr(k, v)
if not self.dict[k] then return nil, "not found" end
self.dict[k] = self.dict[k] + v
return self.dict[k], nil -- newval, err
end
function SimpleDict:get(k)
return self.dict[k], 0 -- value, flags
end
function SimpleDict:get_keys(k)
local keys = {}
for key in pairs(self.dict) do table.insert(keys, key) end
return keys
end
-- Global nginx object
local Nginx = {}
Nginx.__index = Nginx
Nginx.ERR = {}
Nginx.WARN = {}
Nginx.header = {}
function Nginx.log(level, ...)
if not ngx.logs then ngx.logs = {} end
table.insert(ngx.logs, table.concat({...}, " "))
end
function Nginx.print(printed)
if not ngx.printed then ngx.printed = {} end
for str in string.gmatch(table.concat(printed, ""), "([^\n]+)") do
table.insert(ngx.printed, str)
end
end
-- Finds index of a given object in a table
local function find_idx(table, element)
for idx, value in pairs(table) do
if value == element then
return idx
end
end
end
TestPrometheus = {}
function TestPrometheus:setUp()
self.dict = setmetatable({}, SimpleDict)
ngx = setmetatable({shared={metrics=self.dict}}, Nginx)
self.p = prometheus.init("metrics")
self.counter1 = self.p:counter("metric1", "Metric 1")
self.counter2 = self.p:counter("metric2", "Metric 2", {"f2", "f1"})
self.gauge1 = self.p:gauge("gauge1", "Gauge 1")
self.gauge2 = self.p:gauge("gauge2", "Gauge 2", {"f2", "f1"})
self.hist1 = self.p:histogram("l1", "Histogram 1")
self.hist2 = self.p:histogram("l2", "Histogram 2", {"var", "site"})
end
function TestPrometheus:testInit()
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 0)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testErrorUnitialized()
local p = prometheus
p:counter("metric1")
p:histogram("metric2")
p:gauge("metric3")
luaunit.assertEquals(#ngx.logs, 3)
end
function TestPrometheus:testErrorNoMemory()
local counter3 = self.p:counter("willnotfit")
self.counter1:inc(5)
counter3:inc(1)
luaunit.assertEquals(self.dict:get("metric1"), 5)
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 1)
luaunit.assertEquals(self.dict:get("willnotfit"), nil)
luaunit.assertEquals(#ngx.logs, 1)
end
function TestPrometheus:testErrorInvalidMetricName()
local h = self.p:histogram("name with a space", "Histogram")
local g = self.p:gauge("nonprintable\004characters", "Gauge")
local c = self.p:counter("0startswithadigit", "Counter")
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 3)
luaunit.assertEquals(#ngx.logs, 3)
end
function TestPrometheus:testErrorInvalidLabels()
local h = self.p:histogram("hist1", "Histogram", {"le"})
local g = self.p:gauge("count1", "Gauge", {"le"})
local c = self.p:counter("count1", "Counter", {"foo\002"})
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 3)
luaunit.assertEquals(#ngx.logs, 3)
end
function TestPrometheus:testErrorDuplicateMetrics()
self.p:counter("metric1", "Another metric 1")
self.p:counter("l1_count", "Conflicts with Histogram 1")
self.p:counter("l2_sum", "Conflicts with Histogram 2")
self.p:counter("l2_bucket", "Conflicts with Histogram 2")
self.p:gauge("metric1", "Conflicts with Metric 1")
self.p:histogram("l1", "Conflicts with Histogram 1")
self.p:histogram("metric2", "Conflicts with Metric 2")
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 7)
luaunit.assertEquals(#ngx.logs, 7)
end
function TestPrometheus:testErrorNegativeValue()
self.counter1:inc(-5)
luaunit.assertEquals(self.dict:get("metric1"), nil)
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 1)
luaunit.assertEquals(#ngx.logs, 1)
end
function TestPrometheus:testErrorIncorrectLabels()
self.counter1:inc(1, {"should-be-no-labels"})
self.counter2:inc(1, {"too-few-labels"})
self.counter2:inc(1)
self.gauge1:set(1, {"should-be-no-labels"})
self.gauge2:set(1, {"too-few-labels"})
self.gauge2:set(1)
self.hist2:observe(1, {"too", "many", "labels"})
self.hist2:observe(1, {nil, "label"})
self.hist2:observe(1, {"label", nil})
luaunit.assertEquals(self.dict:get("metric1"), nil)
luaunit.assertEquals(self.dict:get("l1_count"), nil)
luaunit.assertEquals(self.dict:get("gauge1"), nil)
luaunit.assertEquals(self.dict:get("gauge2"), nil)
luaunit.assertEquals(self.dict:get("l1_count"), nil)
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 9)
luaunit.assertEquals(#ngx.logs, 9)
end
function TestPrometheus:testNumericLabelValues()
self.counter2:inc(1, {0, 15.5})
self.gauge2:set(1, {0, 15.5})
self.hist2:observe(1, {-3, 90000})
luaunit.assertEquals(self.dict:get('metric2{f2="0",f1="15.5"}'), 1)
luaunit.assertEquals(self.dict:get('gauge2{f2="0",f1="15.5"}'), 1)
luaunit.assertEquals(self.dict:get('l2_sum{var="-3",site="90000"}'), 1)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testNonPrintableLabelValues()
self.counter2:inc(1, {"foo", "baz\189\166qux"})
self.gauge2:set(1, {"z\001", "\002"})
self.hist2:observe(1, {"\166omg", "fooшbar"})
luaunit.assertEquals(self.dict:get('metric2{f2="foo",f1="bazqux"}'), 1)
luaunit.assertEquals(self.dict:get('gauge2{f2="z",f1=""}'), 1)
luaunit.assertEquals(self.dict:get('l2_sum{var="omg",site="foobar"}'), 1)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testNoValues()
self.counter1:inc() -- defaults to 1
self.gauge1:set() -- should produce an error
self.hist1:observe() -- should produce an error
luaunit.assertEquals(self.dict:get("metric1"), 1)
luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 2)
luaunit.assertEquals(#ngx.logs, 2)
end
function TestPrometheus:testCounters()
self.counter1:inc()
self.counter1:inc(4)
self.counter2:inc(1, {"v2", "v1"})
self.counter2:inc(3, {"v2", "v1"})
luaunit.assertEquals(self.dict:get("metric1"), 5)
luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="v1"}'), 4)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testLatencyHistogram()
self.hist1:observe(0.35)
self.hist1:observe(0.4)
self.hist2:observe(0.001, {"ok", "site1"})
self.hist2:observe(0.15, {"ok", "site1"})
luaunit.assertEquals(self.dict:get('l1_bucket{le="00.300"}'), nil)
luaunit.assertEquals(self.dict:get('l1_bucket{le="00.400"}'), 2)
luaunit.assertEquals(self.dict:get('l1_bucket{le="00.500"}'), 2)
luaunit.assertEquals(self.dict:get('l1_bucket{le="Inf"}'), 2)
luaunit.assertEquals(self.dict:get('l1_count'), 2)
luaunit.assertEquals(self.dict:get('l1_sum'), 0.75)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.005"}'), 1)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.100"}'), 1)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.200"}'), 2)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="Inf"}'), 2)
luaunit.assertEquals(self.dict:get('l2_count{var="ok",site="site1"}'), 2)
luaunit.assertEquals(self.dict:get('l2_sum{var="ok",site="site1"}'), 0.151)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testLabelEscaping()
self.counter2:inc(1, {"v2", "\""})
self.counter2:inc(5, {"v2", "\\"})
self.gauge2:set(1, {"v2", "\""})
self.gauge2:set(5, {"v2", "\\"})
self.hist2:observe(0.001, {"ok", "site\"1"})
self.hist2:observe(0.15, {"ok", "site\"1"})
luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="\\""}'), 1)
luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="\\\\"}'), 5)
luaunit.assertEquals(self.dict:get('gauge2{f2="v2",f1="\\""}'), 1)
luaunit.assertEquals(self.dict:get('gauge2{f2="v2",f1="\\\\"}'), 5)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.005"}'), 1)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.100"}'), 1)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.200"}'), 2)
luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="Inf"}'), 2)
luaunit.assertEquals(self.dict:get('l2_count{var="ok",site="site\\"1"}'), 2)
luaunit.assertEquals(self.dict:get('l2_sum{var="ok",site="site\\"1"}'), 0.151)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testCustomBucketer1()
local hist3 = self.p:histogram("l3", "Histogram 3", {"var"}, {1,2,3})
self.hist1:observe(0.35)
hist3:observe(2, {"ok"})
hist3:observe(0.151, {"ok"})
luaunit.assertEquals(self.dict:get('l1_bucket{le="00.300"}'), nil)
luaunit.assertEquals(self.dict:get('l1_bucket{le="00.400"}'), 1)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="1.0"}'), 1)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="2.0"}'), 2)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="3.0"}'), 2)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="Inf"}'), 2)
luaunit.assertEquals(self.dict:get('l3_count{var="ok"}'), 2)
luaunit.assertEquals(self.dict:get('l3_sum{var="ok"}'), 2.151)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testCustomBucketer2()
local hist3 = self.p:histogram("l3", "Histogram 3", {"var"},
{0.000005,5,50000})
hist3:observe(0.000001, {"ok"})
hist3:observe(3, {"ok"})
hist3:observe(7, {"ok"})
hist3:observe(70000, {"ok"})
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="00000.000005"}'), 1)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="00005.000000"}'), 2)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="50000.000000"}'), 3)
luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="Inf"}'), 4)
luaunit.assertEquals(self.dict:get('l3_count{var="ok"}'), 4)
luaunit.assertEquals(self.dict:get('l3_sum{var="ok"}'), 70010.000001)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testCollect()
local hist3 = self.p:histogram("b1", "Bytes", {"var"}, {100, 2000})
self.counter1:inc(5)
self.counter2:inc(2, {"v2", "v1"})
self.counter2:inc(2, {"v2", "v1"})
self.gauge1:set(3)
self.gauge2:set(2, {"v2", "v1"})
self.gauge2:set(5, {"v2", "v1"})
self.hist1:observe(0.000001)
self.hist2:observe(0.000001, {"ok", "site2"})
self.hist2:observe(3, {"ok", "site2"})
self.hist2:observe(7, {"ok", "site2"})
self.hist2:observe(70000, {"ok","site2"})
hist3:observe(50, {"ok"})
hist3:observe(50, {"ok"})
hist3:observe(150, {"ok"})
hist3:observe(5000, {"ok"})
self.p:collect()
assert(find_idx(ngx.printed, "# HELP metric1 Metric 1") ~= nil)
assert(find_idx(ngx.printed, "# TYPE metric1 counter") ~= nil)
assert(find_idx(ngx.printed, "metric1 5") ~= nil)
assert(find_idx(ngx.printed, "# TYPE metric2 counter") ~= nil)
assert(find_idx(ngx.printed, 'metric2{f2="v2",f1="v1"} 4') ~= nil)
assert(find_idx(ngx.printed, "# TYPE gauge1 gauge") ~= nil)
assert(find_idx(ngx.printed, 'gauge1 3') ~= nil)
assert(find_idx(ngx.printed, "# TYPE gauge2 gauge") ~= nil)
assert(find_idx(ngx.printed, 'gauge2{f2="v2",f1="v1"} 5') ~= nil)
assert(find_idx(ngx.printed, "# TYPE b1 histogram") ~= nil)
assert(find_idx(ngx.printed, "# HELP b1 Bytes") ~= nil)
assert(find_idx(ngx.printed, 'b1_bucket{var="ok",le="0100.0"} 2') ~= nil)
assert(find_idx(ngx.printed, 'b1_sum{var="ok"} 5250') ~= nil)
assert(find_idx(ngx.printed, 'l2_bucket{var="ok",site="site2",le="04.000"} 2') ~= nil)
assert(find_idx(ngx.printed, 'l2_bucket{var="ok",site="site2",le="+Inf"} 4') ~= nil)
-- check that type comment exists and is before any samples for the metric.
local type_idx = find_idx(ngx.printed, '# TYPE l1 histogram')
assert (type_idx ~= nil)
assert (ngx.printed[type_idx-1]:find("^l1") == nil)
assert (ngx.printed[type_idx+1]:find("^l1") ~= nil)
luaunit.assertEquals(ngx.logs, nil)
end
function TestPrometheus:testCollectWithPrefix()
local p = prometheus.init("metrics", "test_pref_")
local counter1 = p:counter("metric1", "Metric 1")
local gauge1 = p:gauge("gauge1", "Gauge 1")
local hist1 = p:histogram("b1", "Bytes", {"var"}, {100, 2000})
counter1:inc(5)
gauge1:set(3)
hist1:observe(50, {"ok"})
hist1:observe(50, {"ok"})
hist1:observe(150, {"ok"})
hist1:observe(5000, {"ok"})
p:collect()
assert(find_idx(ngx.printed, "# HELP test_pref_metric1 Metric 1") ~= nil)
assert(find_idx(ngx.printed, "# TYPE test_pref_metric1 counter") ~= nil)
assert(find_idx(ngx.printed, "test_pref_metric1 5") ~= nil)
assert(find_idx(ngx.printed, "# HELP test_pref_gauge1 Gauge 1") ~= nil)
assert(find_idx(ngx.printed, "# TYPE test_pref_gauge1 gauge") ~= nil)
assert(find_idx(ngx.printed, "test_pref_gauge1 3") ~= nil)
assert(find_idx(ngx.printed, "# TYPE test_pref_b1 histogram") ~= nil)
assert(find_idx(ngx.printed, "# HELP test_pref_b1 Bytes") ~= nil)
assert(find_idx(ngx.printed, 'test_pref_b1_bucket{var="ok",le="0100.0"} 2') ~= nil)
assert(find_idx(ngx.printed, 'test_pref_b1_sum{var="ok"} 5250') ~= nil)
end
os.exit(luaunit.run())