aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/scripts/lane
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-12-13 17:22:17 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-12-13 17:22:17 +0100
commitdc7a2bc3a9c8316e17902493b832ca117805d29f (patch)
tree3c1a03edf586869119ef0de03631f6f603650720 /unit_tests/scripts/lane
parent7500a80fc06c5311c46df8f1761f25ae67277fc4 (diff)
downloadlanes-dc7a2bc3a9c8316e17902493b832ca117805d29f.tar.gz
lanes-dc7a2bc3a9c8316e17902493b832ca117805d29f.tar.bz2
lanes-dc7a2bc3a9c8316e17902493b832ca117805d29f.zip
Append all unit tests to depot
Diffstat (limited to 'unit_tests/scripts/lane')
-rw-r--r--unit_tests/scripts/lane/cooperative_shutdown.lua45
-rw-r--r--unit_tests/scripts/lane/stdlib_naming.lua87
-rw-r--r--unit_tests/scripts/lane/tasking_basic.lua74
-rw-r--r--unit_tests/scripts/lane/tasking_cancelling.lua122
-rw-r--r--unit_tests/scripts/lane/tasking_comms_criss_cross.lua53
-rw-r--r--unit_tests/scripts/lane/tasking_communications.lua149
-rw-r--r--unit_tests/scripts/lane/tasking_error.lua49
-rw-r--r--unit_tests/scripts/lane/tasking_join_test.lua65
-rw-r--r--unit_tests/scripts/lane/tasking_send_receive_code.lua91
-rw-r--r--unit_tests/scripts/lane/uncooperative_shutdown.lua24
10 files changed, 759 insertions, 0 deletions
diff --git a/unit_tests/scripts/lane/cooperative_shutdown.lua b/unit_tests/scripts/lane/cooperative_shutdown.lua
new file mode 100644
index 0000000..2649079
--- /dev/null
+++ b/unit_tests/scripts/lane/cooperative_shutdown.lua
@@ -0,0 +1,45 @@
1local lanes = require "lanes"
2
3-- launch lanes that cooperate properly with cancellation request
4
5local lane1 = function()
6 -- loop breaks on cancellation request
7 repeat
8 lanes.sleep(0)
9 until cancel_test()
10 print "lane1 cancelled"
11end
12
13local lane2 = function(linda_)
14 -- loop breaks on lane/linda cancellation
15 repeat
16 local k, v = linda_:receive('k')
17 until v == lanes.cancel_error
18 print "lane2 cancelled"
19end
20
21local lane3 = function()
22 -- this one cooperates too, because of the hook cancellation modes that Lanes will be using
23 -- but not with LuaJIT, because the function is compiled, and we don't call anyone, so no hook triggers
24 repeat until false
25end
26
27
28
29-- the generators
30local g1 = lanes.gen("*", lane1)
31local g2 = lanes.gen("*", lane2)
32local g3 = lanes.gen("*", lane3)
33
34-- launch lanes
35local h1 = g1()
36
37local linda = lanes.linda()
38local h2 = g2(linda)
39
40local h3 = g3()
41
42-- wait until they are both started
43repeat until h1.status == "running" and h2.status == "waiting" and h3.status == "running"
44
45-- let the script terminate, Lanes should not crash at shutdown
diff --git a/unit_tests/scripts/lane/stdlib_naming.lua b/unit_tests/scripts/lane/stdlib_naming.lua
new file mode 100644
index 0000000..2e045c3
--- /dev/null
+++ b/unit_tests/scripts/lane/stdlib_naming.lua
@@ -0,0 +1,87 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local function task(a, b, c)
19 lane_threadname("task("..a..","..b..","..c..")")
20 --error "111" -- testing error messages
21 assert(hey)
22 local v=0
23 for i=a,b,c do
24 v= v+i
25 end
26 return v, hey
27end
28
29local gc_cb = function(name_, status_)
30 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
31end
32
33-- ##################################################################################################
34-- ##################################################################################################
35-- ##################################################################################################
36
37PRINT("\n\n", "---=== Stdlib naming ===---", "\n\n")
38
39local function dump_g(_x)
40 lane_threadname "dump_g"
41 assert(print)
42 print("### dumping _G for '" .. _x .. "'")
43 for k, v in pairs(_G) do
44 print("\t" .. k .. ": " .. type(v))
45 end
46 return true
47end
48
49local function io_os_f(_x)
50 lane_threadname "io_os_f"
51 assert(print)
52 print("### checking io and os libs existence for '" .. _x .. "'")
53 assert(io)
54 assert(os)
55 return true
56end
57
58local function coro_f(_x)
59 lane_threadname "coro_f"
60 assert(print)
61 print("### checking coroutine lib existence for '" .. _x .. "'")
62 assert(coroutine)
63 return true
64end
65
66assert.fails(function() lanes_gen("xxx", {gc_cb = gc_cb}, io_os_f) end)
67
68local stdlib_naming_tests =
69{
70 -- { "", dump_g},
71 -- { "coroutine", dump_g},
72 -- { "io", dump_g},
73 -- { "bit32", dump_g},
74 { "coroutine?", coro_f}, -- in Lua 5.1, the coroutine base library doesn't exist (coroutine table is created when 'base' is opened)
75 { "*", io_os_f},
76 { "io,os", io_os_f},
77 { "io+os", io_os_f},
78 { "/io;os[base{", io_os_f}, -- use unconventional name separators to check that everything works fine
79}
80
81for _, t in ipairs(stdlib_naming_tests) do
82 local f= lanes_gen(t[1], {gc_cb = gc_cb}, t[2]) -- any delimiter will do
83 assert(f(t[1])[1])
84end
85
86PRINT("collectgarbage")
87collectgarbage()
diff --git a/unit_tests/scripts/lane/tasking_basic.lua b/unit_tests/scripts/lane/tasking_basic.lua
new file mode 100644
index 0000000..99be321
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_basic.lua
@@ -0,0 +1,74 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local function task(a, b, c)
19 local new_name = "task("..a..","..b..","..c..")"
20 -- test lane naming change
21 lane_threadname(new_name)
22 assert(lane_threadname() == new_name)
23 --error "111" -- testing error messages
24 assert(hey)
25 local v=0
26 for i=a,b,c do
27 v= v+i
28 end
29 return v, hey
30end
31
32local gc_cb = function(name_, status_)
33 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
34end
35
36-- ##################################################################################################
37-- ##################################################################################################
38-- ##################################################################################################
39
40PRINT("\n\n", "---=== Tasking (basic) ===---", "\n\n")
41
42local task_launch = lanes_gen("", { globals={hey=true}, gc_cb = gc_cb}, task)
43 -- base stdlibs, normal priority
44
45-- 'task_launch' is a factory of multithreaded tasks, we can launch several:
46
47local lane1 = task_launch(100,200,3)
48assert.fails(function() print(lane1[lane1]) end) -- indexing the lane with anything other than a string or a number should fail
49lanes.sleep(0.1) -- give some time so that the lane can set its name
50assert(lane1:get_threadname() == "task(100,200,3)", "Lane name is " .. lane1:get_threadname())
51
52local lane2= task_launch(200,300,4)
53
54-- At this stage, states may be "pending", "running" or "done"
55
56local st1,st2= lane1.status, lane2.status
57PRINT(st1,st2)
58assert(st1=="pending" or st1=="running" or st1=="done")
59assert(st2=="pending" or st2=="running" or st2=="done")
60
61-- Accessing results ([1..N]) pends until they are available
62--
63PRINT("waiting...")
64local v1, v1_hey= lane1[1], lane1[2]
65local v2, v2_hey= lane2[1], lane2[2]
66
67PRINT(v1, v1_hey)
68assert(v1_hey == true)
69
70PRINT(v2, v2_hey)
71assert(v2_hey == true)
72
73assert(lane1.status == "done")
74assert(lane1.status == "done")
diff --git a/unit_tests/scripts/lane/tasking_cancelling.lua b/unit_tests/scripts/lane/tasking_cancelling.lua
new file mode 100644
index 0000000..a4e0fde
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_cancelling.lua
@@ -0,0 +1,122 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local function task(a, b, c)
19 lane_threadname("task("..a..","..b..","..c..")")
20 --error "111" -- testing error messages
21 assert(hey)
22 local v=0
23 for i=a,b,c do
24 v= v+i
25 end
26 return v, hey
27end
28
29local gc_cb = function(name_, status_)
30 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
31end
32
33-- ##################################################################################################
34-- ##################################################################################################
35-- ##################################################################################################
36
37PRINT("\n\n", "---=== Tasking (cancelling) ===---", "\n\n")
38
39local task_launch2 = lanes_gen("", { globals={hey=true}, gc_cb = gc_cb}, task)
40
41local N=999999999
42local lane9= task_launch2(1,N,1) -- huuuuuuge...
43
44-- Wait until state changes "pending"->"running"
45--
46local st
47local t0= os.time()
48while os.time()-t0 < 5 do
49 st= lane9.status
50 io.stderr:write((i==1) and st.." " or '.')
51 if st~="pending" then break end
52end
53PRINT(" "..st)
54
55if st=="error" then
56 local _= lane9[0] -- propagate the error here
57end
58if st=="done" then
59 error("Looping to "..N.." was not long enough (cannot test cancellation)")
60end
61assert(st=="running", "st == " .. st)
62
63-- when running under luajit, the function is JIT-ed, and the instruction count isn't hit, so we need a different hook
64lane9:cancel(jit and "line" or "count", 100) -- 0 timeout, hook triggers cancelslation when reaching the specified count
65
66local t0= os.time()
67while os.time()-t0 < 5 do
68 st= lane9.status
69 io.stderr:write((i==1) and st.." " or '.')
70 if st~="running" then break end
71end
72PRINT(" "..st)
73assert(st == "cancelled", "st is '" .. st .. "' instead of 'cancelled'")
74
75-- cancellation of lanes waiting on a linda
76local limited = lanes_linda("limited")
77assert.fails(function() limited:limit("key", -1) end)
78assert.failsnot(function() limited:limit("key", 1) end)
79-- [[################################################
80limited:send("key", "hello") -- saturate linda
81for k, v in pairs(limited:dump()) do
82 PRINT("limited[" .. tostring(k) .. "] = " .. tostring(v))
83end
84local wait_send = function()
85 local a,b
86 set_finalizer(function() print("wait_send", a, b) end)
87 a,b = limited:send("key", "bybye") -- infinite timeout, returns only when lane is cancelled
88end
89
90local wait_send_lane = lanes.gen("*", wait_send)()
91repeat until wait_send_lane.status == "waiting"
92print "wait_send_lane is waiting"
93wait_send_lane:cancel() -- hard cancel, 0 timeout
94repeat until wait_send_lane.status == "cancelled"
95print "wait_send_lane is cancelled"
96--################################################]]
97local wait_receive = function()
98 local k, v
99 set_finalizer(function() print("wait_receive", k, v) end)
100 k, v = limited:receive("dummy") -- infinite timeout, returns only when lane is cancelled
101end
102
103local wait_receive_lane = lanes.gen("*", wait_receive)()
104repeat until wait_receive_lane.status == "waiting"
105print "wait_receive_lane is waiting"
106wait_receive_lane:cancel() -- hard cancel, 0 timeout
107repeat until wait_receive_lane.status == "cancelled"
108print "wait_receive_lane is cancelled"
109--################################################]]
110local wait_receive_batched = function()
111 local k, v1, v2
112 set_finalizer(function() print("wait_receive_batched", k, v1, v2) end)
113 k, v1, v2 = limited:receive(limited.batched, "dummy", 2) -- infinite timeout, returns only when lane is cancelled
114end
115
116local wait_receive_batched_lane = lanes.gen("*", wait_receive_batched)()
117repeat until wait_receive_batched_lane.status == "waiting"
118print "wait_receive_batched_lane is waiting"
119wait_receive_batched_lane:cancel() -- hard cancel, 0 timeout
120repeat until wait_receive_batched_lane.status == "cancelled"
121print "wait_receive_batched_lane is cancelled"
122--################################################]]
diff --git a/unit_tests/scripts/lane/tasking_comms_criss_cross.lua b/unit_tests/scripts/lane/tasking_comms_criss_cross.lua
new file mode 100644
index 0000000..db63b8e
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_comms_criss_cross.lua
@@ -0,0 +1,53 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local gc_cb = function(name_, status_)
19 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
20end
21
22-- ##################################################################################################
23-- ##################################################################################################
24-- ##################################################################################################
25
26PRINT("\n\n", "---=== Comms criss cross ===---", "\n\n")
27
28-- We make two identical lanes, which are using the same Linda channel.
29--
30local tc = lanes_gen("io", {gc_cb = gc_cb},
31 function(linda, ch_in, ch_out)
32 lane_threadname("criss cross " .. ch_in .. " -> " .. ch_out)
33 local function STAGE(str)
34 io.stderr:write(ch_in..": "..str.."\n")
35 linda:send(nil, ch_out, str)
36 local k,v= linda:receive(nil, ch_in)
37 assert(v==str)
38 end
39 STAGE("Hello")
40 STAGE("I was here first!")
41 STAGE("So what?")
42 end
43)
44
45local linda= lanes_linda("criss cross")
46
47local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms
48
49local _= a[0],b[0] -- waits until they are both ready
50
51PRINT("collectgarbage")
52a, b = nil
53collectgarbage()
diff --git a/unit_tests/scripts/lane/tasking_communications.lua b/unit_tests/scripts/lane/tasking_communications.lua
new file mode 100644
index 0000000..b922973
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_communications.lua
@@ -0,0 +1,149 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local function task(a, b, c)
19 lane_threadname("task("..a..","..b..","..c..")")
20 --error "111" -- testing error messages
21 assert(hey)
22 local v=0
23 for i=a,b,c do
24 v= v+i
25 end
26 return v, hey
27end
28
29local gc_cb = function(name_, status_)
30 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
31end
32
33-- ##################################################################################################
34-- ##################################################################################################
35-- ##################################################################################################
36
37local tables_match = utils.tables_match
38
39local SLEEP = function(...)
40 local k, v = lanes.sleep(...)
41 assert(k == nil and v == "timeout")
42end
43
44PRINT("\n\n", "---=== Communications ===---", "\n\n")
45
46local function WR(...) io.stderr:write(...) end
47
48local chunk= function(linda)
49 local function receive() return linda:receive("->") end
50 local function send(...) local _res, _err = linda:send("<-", ...) assert(_res == true and _err == nil) end
51
52 WR("chunk ", "Lane starts!\n")
53
54 local k,v
55 k,v=receive(); WR("chunk ", v.." received (expecting 1)\n"); assert(k and v==1)
56 k,v=receive(); WR("chunk ", v.." received (expecting 2)\n"); assert(k and v==2)
57 k,v=receive(); WR("chunk ", v.." received (expecting 3)\n"); assert(k and v==3)
58 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil from __lanesconvert)\n"); assert(k and v==nil, "table with __lanesconvert==lanes.null should be received as nil, got " .. tostring(v)) -- a table with __lanesconvert was sent
59 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil)\n"); assert(k and v==nil)
60
61 send(4,5,6); WR("chunk ", "4,5,6 sent\n")
62 send 'aaa'; WR("chunk ", "'aaa' sent\n")
63 send(nil); WR("chunk ", "nil sent\n")
64 send { 'a', 'b', 'c', d=10 }; WR("chunk ","{'a','b','c',d=10} sent\n")
65
66 k,v=receive(); WR("chunk ", v.." received\n"); assert(v==4)
67
68 local subT1 = { "subT1"}
69 local subT2 = { "subT2"}
70 send { subT1, subT2, subT1, subT2}; WR("chunk ", "{ subT1, subT2, subT1, subT2} sent\n")
71
72 WR("chunk ", "Lane ends!\n")
73end
74
75local linda = lanes_linda("communications")
76assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications")
77 --
78 -- ["->"] master -> slave
79 -- ["<-"] slave <- master
80
81WR "test linda:get/set..."
82linda:set("<->", "x", "y", "z")
83local b,x,y,z = linda:get("<->", 1)
84assert(b == 1 and x == "x" and y == nil and z == nil)
85local b,x,y,z = linda:get("<->", 2)
86assert(b == 2 and x == "x" and y == "y" and z == nil)
87local b,x,y,z = linda:get("<->", 3)
88assert(b == 3 and x == "x" and y == "y" and z == "z")
89local b,x,y,z,w = linda:get("<->", 4)
90assert(b == 3 and x == "x" and y == "y" and z == "z" and w == nil)
91local k, x = linda:receive("<->")
92assert(k == "<->" and x == "x")
93local k,y,z = linda:receive(linda.batched, "<->", 2)
94assert(k == "<->" and y == "y" and z == "z")
95linda:set("<->")
96local b,x,y,z,w = linda:get("<->", 4)
97assert(b == 0 and x == nil and y == nil and z == nil and w == nil)
98WR "ok\n"
99
100local function PEEK(...) return linda:get("<-", ...) end
101local function SEND(...) local _res, _err = linda:send("->", ...) assert(_res == true and _err == nil) end
102local function RECEIVE() local k,v = linda:receive(1, "<-") return v end
103
104local comms_lane = lanes_gen("io", {gc_cb = gc_cb, name = "auto"}, chunk)(linda) -- prepare & launch
105
106SEND(1); WR("main ", "1 sent\n")
107SEND(2); WR("main ", "2 sent\n")
108SEND(3); WR("main ", "3 sent\n")
109SEND(setmetatable({"should be ignored"},{__lanesconvert=lanes.null})); WR("main ", "__lanesconvert table sent\n")
110for i=1,40 do
111 WR "."
112 SLEEP(0.0001)
113 assert(PEEK() == 0) -- nothing coming in, yet
114end
115SEND(nil); WR("\nmain ", "nil sent\n")
116
117local a,b,c = RECEIVE(), RECEIVE(), RECEIVE()
118
119print("lane status: " .. comms_lane.status)
120if comms_lane.status == "error" then
121 print(comms_lane:join())
122else
123 WR("main ", tostring(a)..", "..tostring(b)..", "..tostring(c).." received\n")
124end
125
126assert(a==4 and b==5 and c==6)
127
128local aaa = RECEIVE(); WR("main ", aaa.." received\n")
129assert(aaa=='aaa')
130
131local null = RECEIVE(); WR(tostring(null).." received\n")
132assert(null==nil)
133
134local out_t = RECEIVE(); WR(type(out_t).." received\n")
135assert(tables_match(out_t, {'a','b','c',d=10}))
136
137assert(PEEK() == 0)
138SEND(4)
139
140local complex_table = RECEIVE(); WR(type(complex_table).." received\n")
141assert(complex_table[1] == complex_table[3] and complex_table[2] == complex_table[4])
142WR(table.concat({complex_table[1][1],complex_table[2][1],complex_table[3][1],complex_table[4][1]},", "))
143
144WR("collectgarbage")
145comms_lane = nil
146collectgarbage()
147-- wait
148WR("waiting 1s")
149SLEEP(1)
diff --git a/unit_tests/scripts/lane/tasking_error.lua b/unit_tests/scripts/lane/tasking_error.lua
new file mode 100644
index 0000000..1e2347f
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_error.lua
@@ -0,0 +1,49 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local gc_cb = function(name_, status_)
19 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
20end
21
22PRINT("---=== Tasking (error) ===---", "\n\n")
23
24-- a lane that throws immediately the error value it received
25local g = lanes_gen("", {gc_cb = gc_cb}, error)
26local errmsg = "ERROR!"
27
28if true then
29 -- if you index an errored lane, it should throw the error again
30 local lane = g(errmsg)
31 assert.fails(function() return lane[1] end)
32 assert(lane.status == "error")
33 -- even after indexing, joining a lane in error should give nil,<error>
34 local a,b = lane:join()
35 assert(a == nil and string.find(b, errmsg))
36end
37
38if true then
39 local lane = g(errmsg)
40 -- after indexing, joining a lane in error should give nil,<error>
41 local a, b = lane:join()
42 assert(lane.status == "error")
43 assert(a == nil and string.find(b, errmsg))
44 -- even after joining, indexing should raise an error
45 assert.fails(function() return lane[1] end)
46 -- unless we index with a negative value to get the error message
47 local c = lane[-1]
48 assert(c == b)
49end
diff --git a/unit_tests/scripts/lane/tasking_join_test.lua b/unit_tests/scripts/lane/tasking_join_test.lua
new file mode 100644
index 0000000..8f2d4db
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_join_test.lua
@@ -0,0 +1,65 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11local lanes_gen = assert(lanes.gen)
12local lanes_linda = assert(lanes.linda)
13
14-- ##################################################################################################
15-- ##################################################################################################
16-- ##################################################################################################
17
18local gc_cb = function(name_, status_)
19 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
20end
21
22-- ##################################################################################################
23-- ##################################################################################################
24-- ##################################################################################################
25
26local SLEEP = function(...)
27 local k, v = lanes.sleep(...)
28 assert(k == nil and v == "timeout")
29end
30
31PRINT("---=== :join test ===---", "\n\n")
32
33-- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil
34-- (unless [1..n] has been read earlier, in which case it would seemingly
35-- work).
36
37local S= lanes_gen("table", {gc_cb = gc_cb},
38 function(arg)
39 lane_threadname "join test lane"
40 set_finalizer(function() end)
41 local aux= {}
42 for i, v in ipairs(arg) do
43 table.insert(aux, 1, v)
44 end
45 -- unpack was renamed table.unpack in Lua 5.2: cater for both!
46 return (unpack or table.unpack)(aux)
47end)
48
49h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
50-- wait a bit so that the lane has a chance to set its debug name
51SLEEP(0.5)
52print("joining with '" .. h:get_threadname() .. "'")
53local a,b,c,d= h:join()
54if h.status == "error" then
55 print(h:get_threadname(), "error: " , a, b, c, d)
56else
57 print(h:get_threadname(), a,b,c,d)
58 assert(a==14, "a == " .. tostring(a))
59 assert(b==13, "b == " .. tostring(b))
60 assert(c==12, "c == " .. tostring(c))
61 assert(d==nil, "d == " .. tostring(d))
62end
63
64local nameof_type, nameof_name = lanes.nameof(print)
65PRINT("name of " .. nameof_type .. " print = '" .. nameof_name .. "'")
diff --git a/unit_tests/scripts/lane/tasking_send_receive_code.lua b/unit_tests/scripts/lane/tasking_send_receive_code.lua
new file mode 100644
index 0000000..77a4b12
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_send_receive_code.lua
@@ -0,0 +1,91 @@
1local config = { with_timers = false, strip_functions = false, internal_allocator = "libc"}
2local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
3print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
4local lanes = require_lanes_result_1
5
6local require_assert_result_1, require_assert_result_2 = require "_assert"
7print("require_assert_result:", require_assert_result_1, require_assert_result_2)
8
9local utils = lanes.require "_utils"
10local PRINT = utils.MAKE_PRINT()
11
12local lanes_gen = assert(lanes.gen)
13local lanes_linda = assert(lanes.linda)
14
15-- ##################################################################################################
16-- ##################################################################################################
17-- ##################################################################################################
18
19local gc_cb = function(name_, status_)
20 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
21end
22
23-- ##################################################################################################
24-- ##################################################################################################
25-- ##################################################################################################
26
27PRINT("---=== Receive & send of code ===---", "\n")
28
29local upvalue = "123"
30local tostring = tostring
31
32local function chunk2(linda)
33 local utils = require "_utils"
34 local PRINT = utils.MAKE_PRINT()
35 PRINT("here")
36 assert(upvalue == "123") -- even when running as separate thread
37 -- function name & line number should be there even as separate thread
38 --
39 local info= debug.getinfo(1) -- 1 = us
40 --
41 PRINT("linda named-> '" ..tostring(linda).."'")
42 PRINT "debug.getinfo->"
43 for k,v in pairs(info) do PRINT(k,v) end
44
45 -- some assertions are adjusted depending on config.strip_functions, because it changes what we get out of debug.getinfo
46 assert(info.nups == (_VERSION == "Lua 5.1" and 3 or 4), "bad nups " .. info.nups) -- upvalue + config + tostring + _ENV (Lua > 5.2 only)
47 assert(info.what == "Lua", "bad what")
48 --assert(info.name == "chunk2") -- name does not seem to come through
49 assert(config.strip_functions and info.source=="=?" or string.match(info.source, "^@.*tasking_send_receive_code.lua$"), "bad info.source " .. info.source)
50 assert(config.strip_functions and info.short_src=="?" or string.match(info.short_src, "^.*tasking_send_receive_code.lua$"), "bad info.short_src " .. info.short_src)
51 -- These vary so let's not be picky (they're there..)
52 --
53 assert(info.linedefined == 32, "bad linedefined") -- start of 'chunk2'
54 assert(config.strip_functions and info.currentline==-1 or info.currentline > info.linedefined, "bad currentline") -- line of 'debug.getinfo'
55 assert(info.lastlinedefined > info.currentline, "bad lastlinedefined") -- end of 'chunk2'
56 local k,func= linda:receive("down")
57 assert(type(func)=="function", "not a function")
58 assert(k=="down")
59
60 func(linda)
61
62 local k,str= linda:receive("down")
63 assert(str=="ok", "bad receive result")
64
65 linda:send("up", function() return ":)" end, "ok2")
66end
67
68local linda = lanes_linda("auto")
69local t2= lanes_gen("debug,package,string,io", {gc_cb = gc_cb}, chunk2)(linda) -- prepare & launch
70linda:send("down", function(linda) linda:send("up", "ready!") end,
71 "ok")
72-- wait to see if the tiny function gets executed
73--
74local k,s= linda:receive(1, "up")
75if t2.status == "error" then
76 PRINT("t2 error: " , t2:join())
77 assert(false)
78end
79PRINT(s)
80assert(s=="ready!", s .. " is not 'ready!'")
81
82-- returns of the 'chunk2' itself
83--
84local k,f= linda:receive("up")
85assert(type(f)=="function")
86
87local s2= f()
88assert(s2==":)")
89
90local k,ok2= linda:receive("up")
91assert(ok2 == "ok2")
diff --git a/unit_tests/scripts/lane/uncooperative_shutdown.lua b/unit_tests/scripts/lane/uncooperative_shutdown.lua
new file mode 100644
index 0000000..ce7df57
--- /dev/null
+++ b/unit_tests/scripts/lane/uncooperative_shutdown.lua
@@ -0,0 +1,24 @@
1if not package.preload.fixture then
2 error "can't be run outside of UnitTest framework"
3end
4local fixture = require "fixture"
5
6local lanes = require "lanes".configure{shutdown_timeout = 0.001, on_state_create = fixture.on_state_create}
7
8-- launch lanes that blocks forever
9local lane = function()
10 local fixture = require "fixture"
11 fixture.forever()
12end
13
14-- the generator
15local g1 = lanes.gen("*", lane)
16
17-- launch lane
18local h1 = g1()
19
20-- wait until the lane is running
21repeat until h1.status == "running"
22
23-- let the script end, Lanes should throw std::logic_error because the lane did not gracefully terminate
24lanes.finally(fixture.throwing_finalizer)