@@ -63,13 +63,18 @@ func TestObjectsV2ChannelMetadataSetUpdateGetRemove(t *testing.T) {
6363 a .Equal (channelType , res .Data .Type )
6464 }
6565
66- getRes , st , err := pn .GetChannelMetadata ().Include (incl ).Channel (id ).Execute ()
67- a .Nil (err )
68- a .Equal (200 , st .StatusCode )
69- if getRes != nil {
70- a .Equal (statusUpdated , getRes .Data .Status )
71- a .Equal (channelType , getRes .Data .Type )
72- }
66+ // PubNub Objects v2 GET is eventually consistent against SetChannelMetadata writes
67+ // (CI hits a stale replica intermittently). Poll until the updated status propagates
68+ // to the read path before asserting on it; without this the assertion sees the
69+ // previous status ("active" instead of "inactive") and the test fails non-deterministically.
70+ getRes := eventually (t , 10 * time .Second , 250 * time .Millisecond ,
71+ fmt .Sprintf ("channel %s status update propagates to GetChannelMetadata" , id ),
72+ func () (* pubnub.PNGetChannelMetadataResponse , bool ) {
73+ r , _ , e := pn .GetChannelMetadata ().Include (incl ).Channel (id ).Execute ()
74+ return r , e == nil && r != nil && r .Data .Status == statusUpdated
75+ })
76+ a .Equal (statusUpdated , getRes .Data .Status )
77+ a .Equal (channelType , getRes .Data .Type )
7378
7479}
7580
@@ -378,15 +383,17 @@ func TestObjectsV2ChannelMetadataETagConditionalUpdate(t *testing.T) {
378383 a .NotEmpty (res .Data .ETag )
379384 initialETag := res .Data .ETag
380385
381- // Step 2: Get metadata to verify ETag
382- getRes , st , err := pn .GetChannelMetadata ().
383- Include (incl ).
384- Channel (id ).
385- Execute ()
386-
387- a .Nil (err )
388- a .Equal (200 , st .StatusCode )
389- a .NotNil (getRes )
386+ // Step 2: Get metadata to verify ETag.
387+ // PubNub Objects v2 is eventually consistent against just-created objects, so CI
388+ // regularly observes the GET hitting a replica that hasn't seen the Set yet and
389+ // returning 404. Poll until the just-created object becomes visible with the
390+ // expected ETag, otherwise the next line panics dereferencing getRes.Data.
391+ getRes := eventually (t , 10 * time .Second , 250 * time .Millisecond ,
392+ fmt .Sprintf ("channel %s metadata visible to GET after Set (initial ETag)" , id ),
393+ func () (* pubnub.PNGetChannelMetadataResponse , bool ) {
394+ r , _ , e := pn .GetChannelMetadata ().Include (incl ).Channel (id ).Execute ()
395+ return r , e == nil && r != nil && r .Data .ETag == initialETag
396+ })
390397 a .Equal (initialETag , getRes .Data .ETag )
391398
392399 // Step 3: Try to update with incorrect ETag - should fail with 412
@@ -403,16 +410,17 @@ func TestObjectsV2ChannelMetadataETagConditionalUpdate(t *testing.T) {
403410 a .Equal (412 , st .StatusCode )
404411 a .Equal (pubnub .PNPreconditionFailedCategory , st .Category )
405412
406- // Step 4: Verify data was NOT changed
407- getRes , st , err = pn .GetChannelMetadata ().
408- Include (incl ).
409- Channel (id ).
410- Execute ()
411-
412- a .Nil (err )
413- a .Equal (200 , st .StatusCode )
414- a .Equal (initialName , getRes .Data .Name ) // Should still be initial name
415- a .Equal (initialETag , getRes .Data .ETag ) // ETag unchanged
413+ // Step 4: Verify data was NOT changed. Step 3's 412 means the write was rejected on
414+ // the primary, but a subsequent GET can still hit a different replica that's lagging;
415+ // poll until any replica we hit confirms the initial state is intact.
416+ getRes = eventually (t , 10 * time .Second , 250 * time .Millisecond ,
417+ fmt .Sprintf ("channel %s metadata still shows initial state after failed conditional update" , id ),
418+ func () (* pubnub.PNGetChannelMetadataResponse , bool ) {
419+ r , _ , e := pn .GetChannelMetadata ().Include (incl ).Channel (id ).Execute ()
420+ return r , e == nil && r != nil && r .Data .Name == initialName && r .Data .ETag == initialETag
421+ })
422+ a .Equal (initialName , getRes .Data .Name )
423+ a .Equal (initialETag , getRes .Data .ETag )
416424
417425 // Step 5: Update with correct ETag - should succeed
418426 res , st , err = pn .SetChannelMetadata ().
@@ -429,14 +437,14 @@ func TestObjectsV2ChannelMetadataETagConditionalUpdate(t *testing.T) {
429437 a .NotEqual (initialETag , res .Data .ETag ) // ETag should change after update
430438 newETag := res .Data .ETag
431439
432- // Step 6: Verify the update was successful
433- getRes , st , err = pn . GetChannelMetadata () .
434- Include ( incl ).
435- Channel ( id ).
436- Execute ()
437-
438- a . Nil ( err )
439- a . Equal ( 200 , st . StatusCode )
440+ // Step 6: Verify the update was successful. Same read-after-write story as Step 2;
441+ // poll until the update is visible everywhere we land .
442+ getRes = eventually ( t , 10 * time . Second , 250 * time . Millisecond ,
443+ fmt . Sprintf ( "channel %s metadata update propagates to GET (new ETag)" , id ),
444+ func () ( * pubnub. PNGetChannelMetadataResponse , bool ) {
445+ r , _ , e := pn . GetChannelMetadata (). Include ( incl ). Channel ( id ). Execute ()
446+ return r , e == nil && r != nil && r . Data . Name == updatedName && r . Data . ETag == newETag
447+ } )
440448 a .Equal (updatedName , getRes .Data .Name )
441449 a .Equal (newETag , getRes .Data .ETag )
442450}
0 commit comments