v / vlib / goroutines / goroutines_test.v
180 lines · 148 sloc · 3.29 KB · 0480d0b9a920efc39d5ca3c43509a6cf6ebca274
Raw
1// vtest build: !true // goroutines module is experimental; skip on all CIs for now
2// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
3// Use of this source code is governed by an MIT license
4// that can be found in the LICENSE file.
5module goroutines
6
7import time
8
9// Helper function for test_goroutine_create (must be a plain function, not a closure).
10fn goroutine_test_worker(arg voidptr) {
11 // Signal that the goroutine ran by writing to the shared flag
12 if arg != unsafe { nil } {
13 unsafe {
14 mut flag := &bool(arg)
15 *flag = true
16 }
17 }
18}
19
20// Test basic goroutine creation
21fn test_goroutine_create() {
22 mut done := false
23 goroutine_create(voidptr(goroutine_test_worker), voidptr(&done), 0)
24 // Give the goroutine time to run
25 time.sleep(100 * time.millisecond)
26}
27
28// Test channel make
29fn test_chan_make() {
30 c := chan_make(int(sizeof(int)), 10)
31 assert c != unsafe { nil }
32 assert chan_cap(c) == 10
33 assert chan_len(c) == 0
34}
35
36// Test buffered channel send/recv
37fn test_chan_buffered() {
38 c := chan_make(int(sizeof(int)), 5)
39 mut val := 42
40 assert chan_send(c, voidptr(&val), false) == true
41 assert chan_len(c) == 1
42
43 mut recv_val := 0
44 received, ok := chan_recv(c, voidptr(&recv_val), false)
45 assert received == true
46 assert ok == true
47 assert recv_val == 42
48 assert chan_len(c) == 0
49}
50
51// Test channel close
52fn test_chan_close() {
53 c := chan_make(int(sizeof(int)), 1)
54 mut val := 100
55 chan_send(c, voidptr(&val), false)
56 chan_close(c)
57
58 // Should still receive buffered value
59 mut recv_val := 0
60 received, ok := chan_recv(c, voidptr(&recv_val), false)
61 assert received == true
62 // After close with data, ok should be true
63}
64
65// Test GoroutineQueue operations
66fn test_gqueue() {
67 mut q := GoroutineQueue{}
68 assert q.empty()
69 assert q.size == 0
70
71 mut g1 := &Goroutine{
72 id: 1
73 }
74 mut g2 := &Goroutine{
75 id: 2
76 }
77 mut g3 := &Goroutine{
78 id: 3
79 }
80
81 q.push_back(g1)
82 assert !q.empty()
83 assert q.size == 1
84
85 q.push_back(g2)
86 q.push_back(g3)
87 assert q.size == 3
88
89 gp := q.pop()
90 assert gp.id == 1
91 assert q.size == 2
92
93 gp2 := q.pop()
94 assert gp2.id == 2
95
96 gp3 := q.pop()
97 assert gp3.id == 3
98 assert q.empty()
99}
100
101// Test GoroutineList operations
102fn test_glist() {
103 mut l := GoroutineList{}
104 assert l.empty()
105
106 mut g1 := &Goroutine{
107 id: 10
108 }
109 mut g2 := &Goroutine{
110 id: 20
111 }
112
113 l.push(g1)
114 assert !l.empty()
115 assert l.count == 1
116
117 l.push(g2)
118 assert l.count == 2
119
120 // GoroutineList is a stack (LIFO)
121 gp := l.pop()
122 assert gp.id == 20
123
124 gp2 := l.pop()
125 assert gp2.id == 10
126 assert l.empty()
127}
128
129// Test WaitQ operations
130fn test_waitq() {
131 mut q := WaitQ{}
132 assert q.empty()
133
134 mut g1 := &Goroutine{
135 id: 1
136 }
137 mut g2 := &Goroutine{
138 id: 2
139 }
140
141 mut s1 := &Sudog{
142 g: g1
143 }
144 mut s2 := &Sudog{
145 g: g2
146 }
147
148 q.enqueue(s1)
149 assert !q.empty()
150
151 q.enqueue(s2)
152
153 sg := q.dequeue()
154 assert sg.g.id == 1
155
156 sg2 := q.dequeue()
157 assert sg2.g.id == 2
158
159 assert q.empty()
160}
161
162// Test scheduler initialization
163fn test_scheduler_init() {
164 // The scheduler should have been initialized by module init()
165 assert gomaxprocs > 0
166 assert gsched.allp.len > 0
167 assert gsched.allp.len == int(gomaxprocs)
168
169 // P0 should be running (attached to M0)
170 p0 := gsched.allp[0]
171 assert p0.status == .running
172}
173
174// Test goroutine ID allocation
175fn test_goid_allocation() {
176 id1 := assign_goid()
177 id2 := assign_goid()
178 // IDs should be unique and increasing
179 assert id2 > id1
180}
181