feature: add ngx lua github action and test cases. (#7)
* add test cases for ngx lua.
* add more test cases.
* add ngx lua to github action.
* Compatible with lua and ngx lua
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 05972cf..f735fe3 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -19,11 +19,10 @@
on:
pull_request:
push:
- branches:
+ branches:
- master
tags:
- 'v*'
-
jobs:
CI:
@@ -49,10 +48,28 @@
run: |
sudo luarocks install luaunit
sudo luarocks install lua-cjson 2.1.0-1
- - name: 'Run Tests'
+ - name: "Install OpenResty"
+ run: |
+ wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
+ sudo apt-get -y update --fix-missing
+ sudo apt-get -y install software-properties-common
+ sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
+ sudo apt-get update
+ sudo apt-get install openresty-debug
+ - name: "Install test::nginx for testing"
+ run: |
+ sudo apt-get install -y cpanminus
+ sudo cpanm --notest Test::Nginx >build.log 2>&1 || (cat build.log && exit 1)
+ git clone https://github.com/iresty/test-nginx.git test-nginx
+ - name: 'Run Lua Tests'
run: |
cd lib/skywalking
lua util_test.lua
- lua span_test.lua
- lua tracing_context_test.lua
- lua segment_ref_test.lua
\ No newline at end of file
+ lua span_test.lua
+ lua tracing_context_test.lua
+ lua segment_ref_test.lua
+ cd ..
+ - name: 'Run Nginx Lua Tests'
+ run: |
+ export PATH=/usr/local/openresty-debug/nginx/sbin:/usr/local/openresty-debug/luajit/bin:$/usr/local/openresty-debug/bin:$PATH
+ prove -Itest-nginx/lib -r t
diff --git a/lib/skywalking/segment.lua b/lib/skywalking/segment.lua
index 346842d..ea2f33e 100644
--- a/lib/skywalking/segment.lua
+++ b/lib/skywalking/segment.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
-- Segment represents a finished tracing context
-- Including all information to send to the SkyWalking OAP server.
@@ -78,4 +78,4 @@
return segmentBuilder
end
-return Segment
\ No newline at end of file
+return Segment
diff --git a/lib/skywalking/segment_ref.lua b/lib/skywalking/segment_ref.lua
index b7c7f67..7709e90 100644
--- a/lib/skywalking/segment_ref.lua
+++ b/lib/skywalking/segment_ref.lua
@@ -1,20 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
-
+--
local Util = require('util')
local Base64 = require('dependencies/base64')
@@ -71,13 +70,13 @@
-- Deserialize value from the propagated context and initialize the SegmentRef
function SegmentRef:fromSW6Value(value)
- local parts = Util: split(value, '-')
+ local parts = Util.split(value, '-')
if #parts ~= 9 then
return nil
end
- self.trace_id = Util:formatID(Base64.decode(parts[2]))
- self.segment_id = Util:formatID(Base64.decode(parts[3]))
+ self.trace_id = Util.formatID(Base64.decode(parts[2]))
+ self.segment_id = Util.formatID(Base64.decode(parts[3]))
self.span_id = tonumber(parts[4])
self.parent_service_instance_id = tonumber(parts[5])
self.entry_service_instance_id = tonumber(parts[6])
@@ -106,13 +105,13 @@
-- Return string to represent this ref.
function SegmentRef:serialize()
local encodedRef = '1'
- encodedRef = encodedRef .. '-' .. Base64.encode(Util:id2String(self.trace_id))
- encodedRef = encodedRef .. '-' .. Base64.encode(Util:id2String(self.segment_id))
+ encodedRef = encodedRef .. '-' .. Base64.encode(Util.id2String(self.trace_id))
+ encodedRef = encodedRef .. '-' .. Base64.encode(Util.id2String(self.segment_id))
encodedRef = encodedRef .. '-' .. self.span_id
encodedRef = encodedRef .. '-' .. self.parent_service_instance_id
encodedRef = encodedRef .. '-' .. self.entry_service_instance_id
- local networkAddress
+ local networkAddress
if self.network_address_id ~= 0 then
networkAddress = self.network_address_id .. ''
else
diff --git a/lib/skywalking/tracing_context.lua b/lib/skywalking/tracing_context.lua
index 47fcfe6..427202e 100644
--- a/lib/skywalking/tracing_context.lua
+++ b/lib/skywalking/tracing_context.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local Util = require('util')
local Span = require('span')
@@ -58,7 +58,7 @@
return TracingContext:newNoOP()
end
- o.trace_id = Util:newID()
+ o.trace_id = Util.newID()
o.segment_id = o.trace_id
o.service_id = serviceId
o.service_inst_id = serviceInstID
@@ -99,8 +99,8 @@
-- After all active spans finished, this segment will be treated as finished status.
-- Notice, it is different with Java agent, a finished context is still able to recreate new span, and be checked as finished again.
-- This gives the end user more flexibility. Unless it is a real reasonable case, don't call #drainAfterFinished multiple times.
---
--- Return (boolean isSegmentFinished, Segment segment).
+--
+-- Return (boolean isSegmentFinished, Segment segment).
-- Segment has value only when the isSegmentFinished is true
-- if isSegmentFinished == false, SpanList = nil
function TracingContext:drainAfterFinished()
@@ -163,7 +163,7 @@
self.first_span = span
end
- -- span id starts at 0, to fit LUA, we need to plus one.
+ -- span id starts at 0, to fit LUA, we need to plus one.
self.active_spans[span.span_id + 1] = span
self.active_count = self.active_count + 1
return self.owner
@@ -186,4 +186,4 @@
end
---------------------------------------------
-return TracingContext
\ No newline at end of file
+return TracingContext
diff --git a/lib/skywalking/util.lua b/lib/skywalking/util.lua
index 27c1886..8a349fa 100644
--- a/lib/skywalking/util.lua
+++ b/lib/skywalking/util.lua
@@ -1,34 +1,99 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
+local _M = {}
-local Util = {}
+-- for pure Lua
+local split = function(str, delimiter)
+ local t = {}
+ for substr in string.gmatch(str, "[^".. delimiter.. "]*") do
+ if substr ~= nil and string.len(substr) > 0 then
+ table.insert(t,substr)
+ end
+ end
+ return t
+end
+
+local timestamp = function()
+ local _, b = math.modf(os.clock())
+ if b==0 then
+ b='000'
+ else
+ b=tostring(b):sub(3,5)
+ end
+
+ return os.time() * 1000 + b
+end
+
+-- for Nginx Lua
+local ok, ngx_re = pcall(require, "ngx.re")
+if ok then
+ split = ngx_re.split
+ timestamp = function()
+ return ngx.now() * 1000
+ end
+end
+
+_M.split = split
+_M.timestamp = timestamp
+_M.is_ngx_lua = ok
+
local MAX_ID_PART2 = 1000000000
local MAX_ID_PART3 = 100000
-local SEQ = 1
-function Util:newID()
- SEQ = SEQ + 1
- return {Util.timestamp(), math.random( 0, MAX_ID_PART2), math.random( 0, MAX_ID_PART3) + SEQ}
+local random_seed = function ()
+ local seed
+ local frandom = io.open("/dev/urandom", "rb")
+ if frandom then
+ local str = frandom:read(4)
+ frandom:close()
+ if str then
+ local s = 0
+ for i = 1, 4 do
+ s = 256 * s + str:byte(i)
+ end
+ seed = s
+ end
+ end
+
+ if not seed then
+ if _M.is_ngx_lua then
+ seed = ngx.now() * 1000 + ngx.worker.pid()
+ else
+ seed = os.clock()
+ end
+ end
+
+ return seed
+end
+
+math.randomseed(random_seed())
+
+function _M.newID()
+ return {timestamp(), math.random(0, MAX_ID_PART2), math.random(0, MAX_ID_PART3)}
end
-- Format a trace/segment id into an array.
-- An official ID should have three parts separated by '.' and each part of it is a number
-function Util:formatID(str)
- local parts = Util:split(str, '.')
+function _M.formatID(str)
+ local regex = '.'
+ if _M.is_ngx_lua then
+ regex = [[\.]]
+ end
+ local parts = split(str, regex)
if #parts ~= 3 then
return nil
end
@@ -41,36 +106,8 @@
end
-- @param id is an array with length = 3
-function Util:id2String(id)
+function _M.id2String(id)
return id[1] .. '.' .. id[2] .. '.' .. id[3]
end
--- A simulation implementation of Java's System.currentTimeMillis() by following the SkyWalking protocol.
--- Return the difference as string, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
--- But in using os.clock(), I am not sure whether it is accurate enough.
-function Util:timestamp()
- local a,b = math.modf(os.clock())
- if b==0 then
- b='000'
- else
- b=tostring(b):sub(3,5)
- end
-
- return os.time() * 1000 + b
-end
-
--- Split the given string by the delimiter. The delimiter should be a literal string, such as '.', '-'
-function Util:split(str, delimiter)
- local t = {}
-
- for substr in string.gmatch(str, "[^".. delimiter.. "]*") do
- if substr ~= nil and string.len(substr) > 0 then
- table.insert(t,substr)
- end
- end
-
- return t
-end
-
-
-return Util
\ No newline at end of file
+return _M
diff --git a/lib/skywalking/util_test.lua b/lib/skywalking/util_test.lua
index e620017..10d8170 100644
--- a/lib/skywalking/util_test.lua
+++ b/lib/skywalking/util_test.lua
@@ -1,25 +1,25 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local lu = require('luaunit')
local Util = require('util')
TestUtil = {}
- function TestUtil:testNewID()
+ function TestUtil.testNewID()
local id = Util.newID()
lu.assertNotNil(id[1])
@@ -27,11 +27,11 @@
lu.assertNotNil(id[3])
end
- function TestUtil:testTimestamp()
+ function TestUtil.testTimestamp()
local id = Util.timestamp()
lu.assertNotNil(id)
end
-- end TestUtil
-os.exit( lu.LuaUnit.run() )
\ No newline at end of file
+os.exit( lu.LuaUnit.run() )
diff --git a/t/util.t b/t/util.t
new file mode 100644
index 0000000..53f6094
--- /dev/null
+++ b/t/util.t
@@ -0,0 +1,117 @@
+use Test::Nginx::Socket 'no_plan';
+
+use Cwd qw(cwd);
+my $pwd = cwd();
+
+repeat_each(1);
+no_long_string();
+no_shuffle();
+no_root_location();
+log_level('info');
+
+our $HttpConfig = qq{
+ lua_package_path "$pwd/lib/skywalking/?.lua;;";
+ error_log logs/error.log debug;
+ resolver 114.114.114.114 8.8.8.8 ipv6=off;
+ lua_shared_dict tracing_buffer 100m;
+};
+
+run_tests;
+
+__DATA__
+=== TEST 1: timestamp
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('util')
+ local timestamp = util.timestamp()
+ local regex = [[^\d+$]]
+ local m = ngx.re.match(timestamp, regex)
+ if m and tonumber(m[0]) == timestamp then
+ ngx.say(true)
+ else
+ ngx.say(false)
+ end
+ }
+ }
+--- request
+GET /t
+--- response_body
+true
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: newID
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('util')
+ local new_id = util.newID()
+ local regex = [[^\d+$]]
+ ngx.say(#new_id)
+ for i = 1, #new_id, 1 do
+ local m = ngx.re.match(new_id[i], regex)
+ if m and tonumber(m[0]) == new_id[i] then
+ ngx.say(i)
+ end
+ end
+ }
+ }
+--- request
+GET /t
+--- response_body
+3
+1
+2
+3
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: id2String
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('util')
+ local id = util.newID()
+ local id_str = util.id2String(id)
+ local regex = [[^\d+\.\d+\.\d+$]]
+ local m = ngx.re.match(id_str, regex)
+ if m then
+ ngx.say(true)
+ end
+ }
+ }
+--- request
+GET /t
+--- response_body
+true
+--- no_error_log
+[error]
+
+
+
+=== TEST 4: formatID
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('util')
+ local id = util.newID()
+ local id_str = util.id2String(id)
+ local parts = util.formatID(id_str)
+ ngx.say(#parts)
+ }
+ }
+--- request
+GET /t
+--- response_body
+3
+--- no_error_log
+[error]