2121
2222import org .apache .http .Header ;
2323import org .apache .http .HttpHost ;
24+ import org .apache .http .client .AuthCache ;
25+ import org .apache .http .impl .auth .BasicScheme ;
26+ import org .apache .http .impl .client .BasicAuthCache ;
2427import org .apache .http .impl .nio .client .CloseableHttpAsyncClient ;
2528import org .elasticsearch .client .DeadHostStateTests .ConfigurableTimeSupplier ;
2629import org .elasticsearch .client .RestClient .NodeTuple ;
3538import java .util .List ;
3639import java .util .Map ;
3740import java .util .concurrent .CountDownLatch ;
38- import java .util .concurrent .atomic .AtomicInteger ;
3941import java .util .concurrent .TimeUnit ;
42+ import java .util .concurrent .atomic .AtomicInteger ;
4043
4144import static java .util .Collections .singletonList ;
4245import static org .elasticsearch .client .RestClientTestUtil .getHttpMethods ;
4346import static org .hamcrest .Matchers .instanceOf ;
4447import static org .junit .Assert .assertEquals ;
48+ import static org .junit .Assert .assertSame ;
4549import static org .junit .Assert .assertThat ;
4650import static org .junit .Assert .assertTrue ;
4751import static org .junit .Assert .fail ;
@@ -407,8 +411,8 @@ public String toString() {
407411 * blacklist time. It'll revive the node that is closest
408412 * to being revived that the NodeSelector is ok with.
409413 */
410- assertEquals (singletonList (n1 ), RestClient .selectHosts (nodeTuple , blacklist , new AtomicInteger (), NodeSelector .ANY ));
411- assertEquals (singletonList (n2 ), RestClient .selectHosts (nodeTuple , blacklist , new AtomicInteger (), not1 ));
414+ assertEquals (singletonList (n1 ), RestClient .selectNodes (nodeTuple , blacklist , new AtomicInteger (), NodeSelector .ANY ));
415+ assertEquals (singletonList (n2 ), RestClient .selectNodes (nodeTuple , blacklist , new AtomicInteger (), not1 ));
412416
413417 /*
414418 * Try a NodeSelector that excludes all nodes. This should
@@ -449,23 +453,23 @@ private void assertSelectLivingHosts(List<Node> expectedNodes, NodeTuple<List<No
449453 Map <HttpHost , DeadHostState > blacklist , NodeSelector nodeSelector ) throws IOException {
450454 int iterations = 1000 ;
451455 AtomicInteger lastNodeIndex = new AtomicInteger (0 );
452- assertEquals (expectedNodes , RestClient .selectHosts (nodeTuple , blacklist , lastNodeIndex , nodeSelector ));
456+ assertEquals (expectedNodes , RestClient .selectNodes (nodeTuple , blacklist , lastNodeIndex , nodeSelector ));
453457 // Calling it again rotates the set of results
454458 for (int i = 1 ; i < iterations ; i ++) {
455459 Collections .rotate (expectedNodes , 1 );
456460 assertEquals ("iteration " + i , expectedNodes ,
457- RestClient .selectHosts (nodeTuple , blacklist , lastNodeIndex , nodeSelector ));
461+ RestClient .selectNodes (nodeTuple , blacklist , lastNodeIndex , nodeSelector ));
458462 }
459463 }
460464
461465 /**
462- * Assert that {@link RestClient#selectHosts } fails on the provided arguments.
466+ * Assert that {@link RestClient#selectNodes } fails on the provided arguments.
463467 * @return the message in the exception thrown by the failure
464468 */
465- private String assertSelectAllRejected ( NodeTuple <List <Node >> nodeTuple ,
469+ private static String assertSelectAllRejected ( NodeTuple <List <Node >> nodeTuple ,
466470 Map <HttpHost , DeadHostState > blacklist , NodeSelector nodeSelector ) {
467471 try {
468- RestClient .selectHosts (nodeTuple , blacklist , new AtomicInteger (0 ), nodeSelector );
472+ RestClient .selectNodes (nodeTuple , blacklist , new AtomicInteger (0 ), nodeSelector );
469473 throw new AssertionError ("expected selectHosts to fail" );
470474 } catch (IOException e ) {
471475 return e .getMessage ();
@@ -478,5 +482,56 @@ private static RestClient createRestClient() {
478482 new Header [] {}, nodes , null , null , null );
479483 }
480484
485+ public void testRoundRobin () throws IOException {
486+ int numNodes = randomIntBetween (2 , 10 );
487+ AuthCache authCache = new BasicAuthCache ();
488+ List <Node > nodes = new ArrayList <>(numNodes );
489+ for (int i = 0 ; i < numNodes ; i ++) {
490+ Node node = new Node (new HttpHost ("localhost" , 9200 + i ));
491+ nodes .add (node );
492+ authCache .put (node .getHost (), new BasicScheme ());
493+ }
494+ NodeTuple <List <Node >> nodeTuple = new NodeTuple <>(nodes , authCache );
495+
496+ //test the transition from negative to positive values
497+ AtomicInteger lastNodeIndex = new AtomicInteger (-numNodes );
498+ assertNodes (nodeTuple , lastNodeIndex , 50 );
499+ assertEquals (-numNodes + 50 , lastNodeIndex .get ());
500+
501+ //test the highest positive values up to MAX_VALUE
502+ lastNodeIndex .set (Integer .MAX_VALUE - numNodes * 10 );
503+ assertNodes (nodeTuple , lastNodeIndex , numNodes * 10 );
504+ assertEquals (Integer .MAX_VALUE , lastNodeIndex .get ());
505+
506+ //test the transition from MAX_VALUE to MIN_VALUE
507+ //this is the only time where there is most likely going to be a jump from a node
508+ //to another one that's not necessarily the next one.
509+ assertEquals (Integer .MIN_VALUE , lastNodeIndex .incrementAndGet ());
510+ assertNodes (nodeTuple , lastNodeIndex , 50 );
511+ assertEquals (Integer .MIN_VALUE + 50 , lastNodeIndex .get ());
512+ }
481513
514+ private static void assertNodes (NodeTuple <List <Node >> nodeTuple , AtomicInteger lastNodeIndex , int runs ) throws IOException {
515+ int distance = lastNodeIndex .get () % nodeTuple .nodes .size ();
516+ /*
517+ * Collections.rotate is not super intuitive: distance 1 means that the last element will become the first and so on,
518+ * while distance -1 means that the second element will become the first and so on.
519+ */
520+ int expectedOffset = distance > 0 ? nodeTuple .nodes .size () - distance : Math .abs (distance );
521+ for (int i = 0 ; i < runs ; i ++) {
522+ Iterable <Node > selectedNodes = RestClient .selectNodes (nodeTuple , Collections .<HttpHost , DeadHostState >emptyMap (),
523+ lastNodeIndex , NodeSelector .ANY );
524+ List <Node > expectedNodes = nodeTuple .nodes ;
525+ int index = 0 ;
526+ for (Node actualNode : selectedNodes ) {
527+ Node expectedNode = expectedNodes .get ((index + expectedOffset ) % expectedNodes .size ());
528+ assertSame (expectedNode , actualNode );
529+ index ++;
530+ }
531+ expectedOffset --;
532+ if (expectedOffset < 0 ) {
533+ expectedOffset += nodeTuple .nodes .size ();
534+ }
535+ }
536+ }
482537}
0 commit comments