@@ -89,7 +89,7 @@ describe('opencode.opencode_server', function()
8989 assert .is_nil (server .handle )
9090 end )
9191
92- it (' calls on_error when stderr is triggered ' , function ()
92+ it (' calls on_error when stderr callback receives an error ' , function ()
9393 local called = { on_error = false }
9494 local opts_captured = {}
9595 vim .system = function (cmd , opts )
@@ -124,20 +124,90 @@ describe('opencode.opencode_server', function()
124124 end ,
125125 on_error = function (err )
126126 called .on_error = true
127- assert .equals (' some error' , err )
127+ assert .equals (' stream error' , err )
128128 end ,
129129 on_exit = function ()
130130 called .on_exit = true
131131 end ,
132132 })
133- -- Simulate stderr after job is set
134- server .job .stderr (nil , ' some error' )
133+ -- Simulate stderr callback error after job is set
134+ server .job .stderr (' stream error' , nil )
135135 vim .wait (100 , function ()
136136 return called .on_error
137137 end )
138138 assert .is_true (called .on_error )
139139 end )
140140
141+ it (' ignores stderr output before ready when stdout later reports the server URL' , function ()
142+ local called = { on_error = false }
143+ local server = OpencodeServer .new ()
144+
145+ vim .system = function (cmd , opts )
146+ vim .schedule (function ()
147+ opts .stderr (nil , ' Performing one time database migration, may take a few minutes...\n ' )
148+ opts .stderr (nil , ' sqlite-migration:100\n ' )
149+ opts .stdout (nil , ' opencode server listening on http://127.0.0.1:7777' )
150+ end )
151+
152+ return { pid = 45 , kill = function () end }
153+ end
154+
155+ local resolved
156+ server :spawn ({
157+ cwd = ' .' ,
158+ on_ready = function (_ , url )
159+ resolved = url
160+ end ,
161+ on_error = function ()
162+ called .on_error = true
163+ end ,
164+ on_exit = function () end ,
165+ })
166+
167+ vim .wait (100 , function ()
168+ return resolved ~= nil
169+ end )
170+
171+ assert .equals (' http://127.0.0.1:7777' , resolved )
172+ assert .is_false (called .on_error )
173+ end )
174+
175+ it (' rejects startup if the process exits before reporting the server URL' , function ()
176+ local called = { on_error = nil , on_exit = false }
177+ local server = OpencodeServer .new ()
178+
179+ vim .system = function (cmd , opts , on_exit )
180+ vim .schedule (function ()
181+ opts .stderr (nil , ' Database migration failed.\n ' )
182+ on_exit ({ code = 1 , signal = 0 })
183+ end )
184+
185+ return { pid = 46 , kill = function () end }
186+ end
187+
188+ local promise = server :spawn ({
189+ cwd = ' .' ,
190+ on_ready = function ()
191+ called .on_ready = true
192+ end ,
193+ on_error = function (err )
194+ called .on_error = err
195+ end ,
196+ on_exit = function ()
197+ called .on_exit = true
198+ end ,
199+ })
200+
201+ local ok , err = pcall (function ()
202+ promise :wait (100 )
203+ end )
204+
205+ assert .is_false (ok )
206+ assert .truthy (tostring (err ):match (' Database migration failed' ))
207+ assert .truthy (tostring (called .on_error ):match (' Database migration failed' ))
208+ assert .is_true (called .on_exit )
209+ end )
210+
141211 it (' calls on_exit and clears fields when process exits' , function ()
142212 local called = { on_exit = false }
143213 local opts_captured = {}
0 commit comments