@ -292,70 +292,74 @@ func TestCatalogNodes_Blocking(t *testing.T) {
t . Parallel ( )
t . Parallel ( )
a := NewTestAgent ( t , t . Name ( ) , "" )
a := NewTestAgent ( t , t . Name ( ) , "" )
defer a . Shutdown ( )
defer a . Shutdown ( )
testrpc . WaitForTestAgent ( t , a . RPC , "dc1" )
testrpc . WaitForTestAgent ( t , a . RPC , "dc1" , testrpc . WaitForAntiEntropySync ( ) )
// R egister node
// R un the query
args := & structs . DCSpecificRequest {
args := & structs . DCSpecificRequest {
Datacenter : "dc1" ,
Datacenter : "dc1" ,
}
}
var out structs . IndexedNodes
var out structs . IndexedNodes
if err := a . RPC ( "Catalog.ListNodes" , * args , & out ) ; err != nil {
if err := a . RPC ( "Catalog.ListNodes" , * args , & out ) ; err != nil {
t . Fatalf ( "err: %v" , err )
t . Fatalf ( "err: %v" , err )
}
}
// t.Fatal must be called from the main go routine
// Async cause a change
// of the test. Because of this we cannot call
waitIndex := out . Index
// t.Fatal from within the go routines and use
start := time . Now ( )
// an error channel instead.
errch := make ( chan error , 2 )
go func ( ) {
go func ( ) {
testrpc . WaitForTestAgent ( t , a . RPC , "dc1" )
time . Sleep ( 100 * time . Millisecond )
start := time . Now ( )
args := & structs . RegisterRequest {
Datacenter : "dc1" ,
// register a service after the blocking call
Node : "foo" ,
// in order to unblock it.
Address : "127.0.0.1" ,
time . AfterFunc ( 100 * time . Millisecond , func ( ) {
args := & structs . RegisterRequest {
Datacenter : "dc1" ,
Node : "foo" ,
Address : "127.0.0.1" ,
}
var out struct { }
errch <- a . RPC ( "Catalog.Register" , args , & out )
} )
// now block
req , _ := http . NewRequest ( "GET" , fmt . Sprintf ( "/v1/catalog/nodes?wait=3s&index=%d" , out . Index + 1 ) , nil )
resp := httptest . NewRecorder ( )
obj , err := a . srv . CatalogNodes ( resp , req )
if err != nil {
errch <- err
}
}
var out struct { }
// Should block for a while
if err := a . RPC ( "Catalog.Register" , args , & out ) ; err != nil {
if d := time . Since ( start ) ; d < 50 * time . Millisecond {
t . Fatalf ( "err: %v" , err )
errch <- fmt . Errorf ( "too fast: %v" , d )
}
}
} ( )
if idx := getIndex ( t , resp ) ; idx <= out . Index {
const waitDuration = 3 * time . Second
errch <- fmt . Errorf ( "bad: %v" , idx )
}
nodes := obj . ( structs . Nodes )
// Re-run the query, if errantly woken up with no change, resume blocking.
if len ( nodes ) != 2 {
var elapsed time . Duration
errch <- fmt . Errorf ( "bad: %v" , obj )
RUN_BLOCKING_QUERY :
req , err := http . NewRequest ( "GET" , fmt . Sprintf ( "/v1/catalog/nodes?wait=%s&index=%d" ,
waitDuration . String ( ) ,
waitIndex ) , nil )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
resp := httptest . NewRecorder ( )
obj , err := a . srv . CatalogNodes ( resp , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
elapsed = time . Since ( start )
idx := getIndex ( t , resp )
if idx < waitIndex {
t . Fatalf ( "bad: %v" , idx )
} else if idx == waitIndex {
if elapsed > waitDuration {
// This should prevent the loop from running longer than the
// waitDuration
t . Fatalf ( "too slow: %v" , elapsed )
}
}
errch <- nil
goto RUN_BLOCKING_QUERY
} ( )
}
// wait for both go routines to return
// Should block at least 100ms before getting the changed results
if err := <- errch ; err != nil {
if e lapsed < 100 * time . Millisecond {
t . Fatal ( err )
t . Fatal f( "too fast: %v" , elapsed )
}
}
if err := <- errch ; err != nil {
t . Fatal ( err )
nodes := obj . ( structs . Nodes )
if len ( nodes ) != 2 {
t . Fatalf ( "bad: %v" , obj )
}
}
}
}
func TestCatalogNodes_DistanceSort ( t * testing . T ) {
func TestCatalogNodes_DistanceSort ( t * testing . T ) {