@@ -38,6 +38,32 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
38
38
network .BeginMining (blockTime )
39
39
subject .WaitTillChain (ctx , kit .HeightAtLeast (targetHeight ))
40
40
41
+ // mkStableExecute creates a stable execution wrapper that ensures the chain doesn't
42
+ // advance during test execution to avoid flaky tests due to chain reorgs
43
+ mkStableExecute := func (getTipSet func (t * testing.T ) * types.TipSet ) func (fn func ()) * types.TipSet {
44
+ return func (fn func ()) * types.TipSet {
45
+ // Create a stable execute function that takes the test context
46
+ return func (t * testing.T ) * types.TipSet {
47
+ beforeTs := getTipSet (t )
48
+ for {
49
+ select {
50
+ case <- ctx .Done ():
51
+ t .Fatalf ("context cancelled during stable execution: %v" , ctx .Err ())
52
+ default :
53
+ }
54
+
55
+ fn ()
56
+ afterTs := getTipSet (t )
57
+ if beforeTs .Equals (afterTs ) {
58
+ // Chain hasn't changed during execution, safe to return
59
+ return beforeTs
60
+ }
61
+ beforeTs = afterTs
62
+ }
63
+ }(t ) // Pass the current test context
64
+ }
65
+ }
66
+
41
67
var (
42
68
heaviest = func (t * testing.T ) * types.TipSet {
43
69
head , err := subject .ChainHead (ctx )
@@ -302,32 +328,49 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
302
328
if test .when != nil {
303
329
test .when (t )
304
330
}
305
- gotResponseCode , gotResponseBody := subject .DoRawRPCRequest (t , 2 , test .request )
306
- require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
331
+
332
+ // Use stable execute to ensure the test doesn't straddle tipsets
333
+ stableExecute := mkStableExecute (test .wantTipSet )
334
+ if test .wantTipSet == nil {
335
+ stableExecute = mkStableExecute (heaviest )
336
+ }
337
+
338
+ var gotResponseCode int
339
+ var gotResponseBody []byte
307
340
var resultOrError struct {
308
341
Result * types.TipSet `json:"result,omitempty"`
309
342
Error * struct {
310
343
Code int `json:"code,omitempty"`
311
344
Message string `json:"message,omitempty"`
312
345
} `json:"error,omitempty"`
313
346
}
314
- require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
347
+
348
+ stableTipSet := stableExecute (func () {
349
+ gotResponseCode , gotResponseBody = subject .DoRawRPCRequest (t , 2 , test .request )
350
+ if gotResponseCode == test .wantResponseStatus {
351
+ require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
352
+ }
353
+ })
354
+ require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
355
+
315
356
if test .wantErr != "" {
316
357
require .Nil (t , resultOrError .Result )
317
- require .Contains (t , resultOrError .Error .Message , test .wantErr )
358
+ if resultOrError .Error != nil {
359
+ require .Contains (t , resultOrError .Error .Message , test .wantErr )
360
+ }
318
361
} else {
319
362
require .Nil (t , resultOrError .Error )
320
- require .Equal (t , test .wantTipSet (t ), resultOrError .Result )
363
+ if test .wantTipSet != nil {
364
+ require .Equal (t , stableTipSet , resultOrError .Result )
365
+ }
321
366
}
322
367
})
323
368
}
324
369
})
325
370
t .Run ("StateGetActor" , func (t * testing.T ) {
326
- v1StateGetActor := func (t * testing.T , ts func (* testing.T ) * types.TipSet ) func (* testing.T ) * types.Actor {
327
- return func (t * testing.T ) * types.Actor {
328
- wantActor , err := subject .StateGetActor (ctx , miner .ActorAddr , ts (t ).Key ())
329
- require .NoError (t , err )
330
- return wantActor
371
+ v1StateGetActor := func (ts * types.TipSet ) func () (* types.Actor , error ) {
372
+ return func () (* types.Actor , error ) {
373
+ return subject .StateGetActor (ctx , miner .ActorAddr , ts .Key ())
331
374
}
332
375
}
333
376
@@ -336,7 +379,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
336
379
when func (t * testing.T )
337
380
request string
338
381
wantResponseStatus int
339
- wantActor func (t * testing.T ) * types.Actor
382
+ wantTipSet func (t * testing.T ) * types.TipSet
340
383
wantErr string
341
384
}{
342
385
{
@@ -349,7 +392,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
349
392
name : "latest tag is ok" ,
350
393
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetActor","params":["f01000",{"tag":"latest"}],"id":1}` ,
351
394
wantResponseStatus : http .StatusOK ,
352
- wantActor : v1StateGetActor ( t , heaviest ) ,
395
+ wantTipSet : heaviest ,
353
396
},
354
397
{
355
398
name : "finalized tag when f3 disabled falls back to ec" ,
@@ -358,7 +401,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
358
401
},
359
402
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetActor","params":["f01000",{"tag":"finalized"}],"id":1}` ,
360
403
wantResponseStatus : http .StatusOK ,
361
- wantActor : v1StateGetActor ( t , ecFinalized ) ,
404
+ wantTipSet : ecFinalized ,
362
405
},
363
406
{
364
407
name : "finalized tag is ok" ,
@@ -370,7 +413,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
370
413
},
371
414
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetActor","params":["f01000",{"tag":"finalized"}],"id":1}` ,
372
415
wantResponseStatus : http .StatusOK ,
373
- wantActor : v1StateGetActor ( t , tipSetAtHeight (f3FinalizedEpoch ) ),
416
+ wantTipSet : tipSetAtHeight (f3FinalizedEpoch ),
374
417
},
375
418
{
376
419
name : "height with anchor to latest" ,
@@ -382,31 +425,49 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
382
425
},
383
426
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetActor","params":["f01000",{"height":{"at":15,"anchor":{"tag":"latest"}}}],"id":1}` ,
384
427
wantResponseStatus : http .StatusOK ,
385
- wantActor : v1StateGetActor ( t , tipSetAtHeight (15 ) ),
428
+ wantTipSet : tipSetAtHeight (15 ),
386
429
},
387
430
} {
388
431
t .Run (test .name , func (t * testing.T ) {
389
432
if test .when != nil {
390
433
test .when (t )
391
434
}
392
- gotResponseCode , gotResponseBody := subject .DoRawRPCRequest (t , 2 , test .request )
393
- require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
394
435
436
+ // Use stable execute to ensure the test doesn't straddle tipsets
437
+ stableExecute := mkStableExecute (test .wantTipSet )
438
+ if test .wantTipSet == nil {
439
+ stableExecute = mkStableExecute (heaviest )
440
+ }
441
+
442
+ var gotResponseCode int
443
+ var gotResponseBody []byte
395
444
var resultOrError struct {
396
445
Result * types.Actor `json:"result,omitempty"`
397
446
Error * struct {
398
447
Code int `json:"code,omitempty"`
399
448
Message string `json:"message,omitempty"`
400
449
} `json:"error,omitempty"`
401
450
}
402
- require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
451
+
452
+ stableTipSet := stableExecute (func () {
453
+ gotResponseCode , gotResponseBody = subject .DoRawRPCRequest (t , 2 , test .request )
454
+ if gotResponseCode == test .wantResponseStatus {
455
+ require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
456
+ }
457
+ })
458
+ require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
403
459
404
460
if test .wantErr != "" {
405
461
require .Nil (t , resultOrError .Result )
406
- require .Contains (t , resultOrError .Error .Message , test .wantErr )
462
+ if resultOrError .Error != nil {
463
+ require .Contains (t , resultOrError .Error .Message , test .wantErr )
464
+ }
407
465
} else {
408
- wantActor := test .wantActor (t )
409
- require .Equal (t , wantActor , resultOrError .Result )
466
+ if test .wantTipSet != nil && stableTipSet != nil {
467
+ wantActor , err := v1StateGetActor (stableTipSet )()
468
+ require .NoError (t , err )
469
+ require .Equal (t , wantActor , resultOrError .Result )
470
+ }
410
471
}
411
472
})
412
473
}
@@ -417,7 +478,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
417
478
when func (t * testing.T )
418
479
request string
419
480
wantResponseStatus int
420
- wantID func (* testing.T ) * address. Address
481
+ wantTipSet func (t * testing.T ) * types. TipSet
421
482
wantErr string
422
483
}{
423
484
{
@@ -430,12 +491,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
430
491
name : "latest tag is ok" ,
431
492
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetID","params":["f01000",{"tag":"latest"}],"id":1}` ,
432
493
wantResponseStatus : http .StatusOK ,
433
- wantID : func (t * testing.T ) * address.Address {
434
- tsk := heaviest (t ).Key ()
435
- wantID , err := subject .StateLookupID (ctx , miner .ActorAddr , tsk )
436
- require .NoError (t , err )
437
- return & wantID
438
- },
494
+ wantTipSet : heaviest ,
439
495
},
440
496
{
441
497
name : "finalized tag when f3 disabled falls back to ec" ,
@@ -444,33 +500,43 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
444
500
},
445
501
request : `{"jsonrpc":"2.0","method":"Filecoin.StateGetID","params":["f01000",{"tag":"finalized"}],"id":1}` ,
446
502
wantResponseStatus : http .StatusOK ,
447
- wantID : func (t * testing.T ) * address.Address {
448
- tsk := tipSetAtHeight (f3FinalizedEpoch )(t ).Key ()
449
- wantID , err := subject .StateLookupID (ctx , miner .ActorAddr , tsk )
450
- require .NoError (t , err )
451
- return & wantID
452
- },
503
+ wantTipSet : tipSetAtHeight (f3FinalizedEpoch ),
453
504
},
454
505
} {
455
506
t .Run (test .name , func (t * testing.T ) {
456
507
if test .when != nil {
457
508
test .when (t )
458
509
}
459
- gotResponseCode , gotResponseBody := subject .DoRawRPCRequest (t , 2 , test .request )
460
- require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
461
510
511
+ // Use stable execute to ensure the test doesn't straddle tipsets
512
+ stableExecute := mkStableExecute (test .wantTipSet )
513
+ if test .wantTipSet == nil {
514
+ stableExecute = mkStableExecute (heaviest )
515
+ }
516
+
517
+ var gotResponseCode int
518
+ var gotResponseBody []byte
462
519
var resultOrError struct {
463
520
Result * address.Address `json:"result,omitempty"`
464
521
Error * struct {
465
522
Code int `json:"code,omitempty"`
466
523
Message string `json:"message,omitempty"`
467
524
} `json:"error,omitempty"`
468
525
}
469
- require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
526
+
527
+ _ = stableExecute (func () {
528
+ gotResponseCode , gotResponseBody = subject .DoRawRPCRequest (t , 2 , test .request )
529
+ if gotResponseCode == test .wantResponseStatus {
530
+ require .NoError (t , json .Unmarshal (gotResponseBody , & resultOrError ))
531
+ }
532
+ })
533
+ require .Equal (t , test .wantResponseStatus , gotResponseCode , string (gotResponseBody ))
470
534
471
535
if test .wantErr != "" {
472
536
require .Nil (t , resultOrError .Result )
473
- require .Contains (t , resultOrError .Error .Message , test .wantErr )
537
+ if resultOrError .Error != nil {
538
+ require .Contains (t , resultOrError .Error .Message , test .wantErr )
539
+ }
474
540
}
475
541
})
476
542
}
0 commit comments