@@ -193,13 +193,13 @@ func TestEvNode_PostsToDA(t *testing.T) {
193193 _ , err = cli .Post (ctx , "/tx" , key , value )
194194 require .NoError (t , err )
195195
196- require . Eventually ( t , func () bool {
196+ waitFor ( ctx , t , 30 * time . Second , 2 * time . Second , func () bool {
197197 res , err := cli .Get (ctx , "/kv?key=" + key )
198198 if err != nil {
199199 return false
200200 }
201201 return string (res ) == value
202- }, 30 * time . Second , time . Second , "ev-node should serve the kv value" )
202+ }, "ev-node should serve the kv value" )
203203
204204 // 6) Assert data landed on DA via celestia-node blob RPC (namespace ev-data)
205205 daRPCAddr := fmt .Sprintf ("http://127.0.0.1:%s" , bridgeNetInfo .External .Ports .RPC )
@@ -212,7 +212,7 @@ func TestEvNode_PostsToDA(t *testing.T) {
212212 require .NoError (t , err , "tm rpc client" )
213213
214214 var pfbHeight int64
215- require . Eventually ( t , func () bool {
215+ waitFor ( ctx , t , time . Minute , 5 * time . Second , func () bool {
216216 res , err := tmRPC .TxSearch (ctx , "message.action='/celestia.blob.v1.MsgPayForBlobs'" , false , nil , nil , "desc" )
217217 if err != nil || len (res .Txs ) == 0 {
218218 return false
@@ -235,9 +235,9 @@ func TestEvNode_PostsToDA(t *testing.T) {
235235 }
236236 }
237237 return false
238- }, 2 * time . Minute , 5 * time . Second , "expected a PayForBlobs tx on celestia-app" )
238+ }, "expected a PayForBlobs tx on celestia-app" )
239239
240- require . Eventually ( t , func () bool {
240+ waitFor ( ctx , t , time . Minute , 5 * time . Second , func () bool {
241241 if pfbHeight == 0 {
242242 return false
243243 }
@@ -252,7 +252,7 @@ func TestEvNode_PostsToDA(t *testing.T) {
252252 }
253253 }
254254 return false
255- }, 6 * time . Minute , 5 * time . Second , "expected blob in DA for namespace ev-data" )
255+ }, "expected blob in DA for namespace ev-data" )
256256}
257257
258258// newHTTPClient is a small helper to avoid importing the docker_e2e client.
@@ -309,3 +309,25 @@ func getEnvDefault(key, def string) string {
309309 }
310310 return def
311311}
312+
313+ // waitFor polls condition until it returns true, context is cancelled, or timeout expires.
314+ func waitFor (ctx context.Context , t * testing.T , timeout , interval time.Duration , condition func () bool , msg string ) {
315+ t .Helper ()
316+ deadline := time .Now ().Add (timeout )
317+ ticker := time .NewTicker (interval )
318+ defer ticker .Stop ()
319+
320+ for {
321+ select {
322+ case <- ctx .Done ():
323+ t .Fatalf ("%s: context cancelled: %v" , msg , ctx .Err ())
324+ case <- ticker .C :
325+ if time .Now ().After (deadline ) {
326+ t .Fatalf ("%s: timed out after %v" , msg , timeout )
327+ }
328+ if condition () {
329+ return
330+ }
331+ }
332+ }
333+ }
0 commit comments