This is an automated email from the ASF dual-hosted git repository.

jdyer pushed a commit to branch feature/SOLR-17516-c
in repository https://gitbox.apache.org/repos/asf/solr.git

commit c7e306c33e1abac62589d2a1d1859585e18806f3
Author: jdyer1 <[email protected]>
AuthorDate: Mon Oct 28 17:57:40 2024 -0500

    Add additional unit tests
---
 .../client/solrj/impl/LBHttp2SolrClientTest.java   | 448 +++++++++++++--------
 1 file changed, 272 insertions(+), 176 deletions(-)

diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java
 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java
index 5f55b353c0d..63ccd04b814 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.client.solrj.impl;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -28,6 +29,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import org.apache.solr.SolrTestCase;
 import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.MapSolrParams;
@@ -37,200 +39,294 @@ import org.junit.Test;
 /** Test the LBHttp2SolrClient. */
 public class LBHttp2SolrClientTest extends SolrTestCase {
 
-  /**
-   * Test method for {@link LBHttp2SolrClient.Builder} that validates that the 
query param keys
-   * passed in by the base <code>Http2SolrClient
-   * </code> instance are used by the LBHttp2SolrClient.
-   */
-  @Test
-  public void testLBHttp2SolrClientWithTheseParamNamesInTheUrl() {
-    String url = "http://127.0.0.1:8080";;
-    Set<String> urlParamNames = new HashSet<>(2);
-    urlParamNames.add("param1");
-
-    try (Http2SolrClient http2SolrClient =
-            new 
Http2SolrClient.Builder(url).withTheseParamNamesInTheUrl(urlParamNames).build();
-        LBHttp2SolrClient testClient =
-            new LBHttp2SolrClient.Builder(http2SolrClient, new 
LBSolrClient.Endpoint(url))
-                .build()) {
-
-      assertArrayEquals(
-          "Wrong urlParamNames found in lb client.",
-          urlParamNames.toArray(),
-          testClient.getUrlParamNames().toArray());
-      assertArrayEquals(
-          "Wrong urlParamNames found in base client.",
-          urlParamNames.toArray(),
-          http2SolrClient.getUrlParamNames().toArray());
-    }
-  }
-
-  @Test
-  public void testAsyncWithFailures() {
-
-    // This demonstrates that the failing endpoint always gets retried, and it 
is up to the user
-    // to remove any failing nodes if desired.
-
-    LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
-    LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
-    List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
-
-    Http2SolrClient.Builder b =
-        new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
-    ;
-    try (MockHttp2SolrClient client = new 
MockHttp2SolrClient("http://base.url";, b);
-        LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, 
ep1, ep2).build()) {
-
-      for (int j = 0; j < 2; j++) {
-        // first time Endpoint One will return error code 500.
-        // second time Endpoint One will be healthy
-
-        String basePathToSucceed;
-        if (j == 0) {
-          client.basePathToFail = ep1.getBaseUrl();
-          basePathToSucceed = ep2.getBaseUrl();
-        } else {
-          client.basePathToFail = ep2.getBaseUrl();
-          basePathToSucceed = ep1.getBaseUrl();
-        }
+    /**
+     * Test method for {@link LBHttp2SolrClient.Builder} that validates that 
the query param keys
+     * passed in by the base <code>Http2SolrClient
+     * </code> instance are used by the LBHttp2SolrClient.
+     */
+    @Test
+    public void testLBHttp2SolrClientWithTheseParamNamesInTheUrl() {
+        String url = "http://127.0.0.1:8080";;
+        Set<String> urlParamNames = new HashSet<>(2);
+        urlParamNames.add("param1");
+
+        try (Http2SolrClient http2SolrClient =
+                     new 
Http2SolrClient.Builder(url).withTheseParamNamesInTheUrl(urlParamNames).build();
+             LBHttp2SolrClient testClient =
+                     new LBHttp2SolrClient.Builder(http2SolrClient, new 
LBSolrClient.Endpoint(url))
+                             .build()) {
 
-        for (int i = 0; i < 10; i++) {
-          // i: we'll try 10 times to see if it behaves the same every time.
-
-          QueryRequest queryRequest = new QueryRequest(new 
MapSolrParams(Map.of("q", "" + i)));
-          LBSolrClient.Req req = new LBSolrClient.Req(queryRequest, 
endpointList);
-          String iterMessage = "iter j/i " + j + "/" + i;
-          try {
-            testClient.requestAsync(req).get(1, TimeUnit.MINUTES);
-          } catch (InterruptedException ie) {
-            Thread.currentThread().interrupt();
-            fail("interrupted");
-          } catch (TimeoutException | ExecutionException e) {
-            fail(iterMessage + " Response ended in failure: " + e);
-          }
-          if (i == 0) {
-            // When j=0, "endpoint one" fails.
-            // The first time around (i) it tries the first, then the second.
-            //
-            // With j=0 and i>0, it only tries "endpoint two".
-            //
-            // When j=1 and i=0, "endpoint two" starts failing.
-            // So it tries both it and "endpoint one"
-            //
-            // With j=1 and i>0, it only tries "endpoint one".
-            assertEquals(iterMessage, 2, client.lastBasePaths.size());
-
-            String failedBasePath = client.lastBasePaths.remove(0);
-            assertEquals(iterMessage, client.basePathToFail, failedBasePath);
-          } else {
-            // The first endpoint does not give the exception, it doesn't 
retry.
-            assertEquals(iterMessage, 1, client.lastBasePaths.size());
-          }
-          String successBasePath = client.lastBasePaths.remove(0);
-          assertEquals(iterMessage, basePathToSucceed, successBasePath);
+            assertArrayEquals(
+                    "Wrong urlParamNames found in lb client.",
+                    urlParamNames.toArray(),
+                    testClient.getUrlParamNames().toArray());
+            assertArrayEquals(
+                    "Wrong urlParamNames found in base client.",
+                    urlParamNames.toArray(),
+                    http2SolrClient.getUrlParamNames().toArray());
         }
-      }
     }
-  }
-
-  @Test
-  public void testAsync() {
-    LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
-    LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
-    List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
-
-    Http2SolrClient.Builder b =
-        new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
-    try (MockHttp2SolrClient client = new 
MockHttp2SolrClient("http://base.url";, b);
-        LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, 
ep1, ep2).build()) {
-
-      int limit = 10; // For simplicity use an even limit
-      List<CompletableFuture<LBSolrClient.Rsp>> responses = new ArrayList<>();
-
-      for (int i = 0; i < limit; i++) {
-        QueryRequest queryRequest = new QueryRequest(new 
MapSolrParams(Map.of("q", "" + i)));
-        LBSolrClient.Req req = new LBSolrClient.Req(queryRequest, 
endpointList);
-        responses.add(testClient.requestAsync(req));
-      }
-
-      QueryRequest[] queryRequests = new QueryRequest[limit];
-      int numEndpointOne = 0;
-      int numEndpointTwo = 0;
-      for (int i = 0; i < limit; i++) {
-        SolrRequest<?> lastSolrReq = client.lastSolrRequests.get(i);
-        assertTrue(lastSolrReq instanceof QueryRequest);
-        QueryRequest lastQueryReq = (QueryRequest) lastSolrReq;
-        int index = Integer.parseInt(lastQueryReq.getParams().get("q"));
-        assertNull("Found same request twice: " + index, queryRequests[index]);
-        queryRequests[index] = lastQueryReq;
-        if (lastQueryReq.getBasePath().equals(ep1.toString())) {
-          numEndpointOne++;
-        } else if (lastQueryReq.getBasePath().equals(ep2.toString())) {
-          numEndpointTwo++;
-        }
 
-        LBSolrClient.Rsp lastRsp = null;
-        try {
-          lastRsp = responses.get(index).get();
-        } catch (InterruptedException ie) {
-          Thread.currentThread().interrupt();
-          fail("interrupted");
-        } catch (ExecutionException ee) {
-          fail("Response " + index + " ended in failure: " + ee);
+    @Test
+    public void testSynchronous() throws Exception {
+        LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
+        LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
+        List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
+
+        Http2SolrClient.Builder b =
+                new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
+        ;
+        try (MockHttpSolrClient client = new 
MockHttpSolrClient("http://base.url";, b);
+             LBHttp2SolrClient testClient = new 
LBHttp2SolrClient.Builder(client, ep1, ep2).build()) {
+
+            String lastEndpoint = null;
+            for (int i = 0; i < 10; i++) {
+                String qValue = "Query Number: " + i;
+                QueryRequest queryRequest = new QueryRequest(new 
MapSolrParams(Map.of("q", qValue)));
+                LBSolrClient.Req req = new LBSolrClient.Req(queryRequest, 
endpointList);
+                LBSolrClient.Rsp response = testClient.request(req);
+
+                String expectedEndpoint =
+                        ep1.toString().equals(lastEndpoint) ? ep2.toString() : 
ep1.toString();
+                assertEquals(
+                        "There should be round-robin load balancing.", 
expectedEndpoint, response.server);
+                checkSynchonousResponseContent(response, qValue);
+            }
         }
-        NamedList<Object> lastResponse = lastRsp.getResponse();
+    }
+
+    @Test
+    public void testSynchronousWihFalures() throws Exception {
+        LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
+        LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
+        List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
+
+        Http2SolrClient.Builder b =
+                new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
+        ;
+        try (MockHttpSolrClient client = new 
MockHttpSolrClient("http://base.url";, b);
+             LBHttp2SolrClient testClient = new 
LBHttp2SolrClient.Builder(client, ep1, ep2).build()) {
 
-        // The Mock will return {"response": index}.
-        assertEquals("" + index, lastResponse.get("response"));
-      }
+            client.basePathToFail = ep1.getBaseUrl();
+            String basePathToSucceed = ep2.getBaseUrl();
+            String qValue = "First time";
 
-      // It is the user's responsibility to shuffle the endpoints when using
-      // async.  LB Http Solr Client will always try the passed-in endpoints
-      // in order.  In this case, endpoint 1 gets all the requests!
-      assertEquals(limit, numEndpointOne);
-      assertEquals(0, numEndpointTwo);
+            for (int i = 0; i < 5; i++) {
+                LBSolrClient.Req req =
+                        new LBSolrClient.Req(
+                                new QueryRequest(new MapSolrParams(Map.of("q", 
qValue))), endpointList);
+                LBSolrClient.Rsp response = testClient.request(req);
+                assertEquals(
+                        "The healthy node 'endpoint two' should have served 
the request: " + i,
+                        basePathToSucceed,
+                        response.server);
+                checkSynchonousResponseContent(response, qValue);
+            }
 
-      assertEquals(limit, client.lastSolrRequests.size());
-      assertEquals(limit, client.lastCollections.size());
+            client.basePathToFail = ep2.getBaseUrl();
+            basePathToSucceed = ep1.getBaseUrl();
+            qValue = "Second time";
+
+            for (int i = 0; i < 5; i++) {
+                LBSolrClient.Req req =
+                        new LBSolrClient.Req(
+                                new QueryRequest(new MapSolrParams(Map.of("q", 
qValue))), endpointList);
+                LBSolrClient.Rsp response = testClient.request(req);
+                assertEquals(
+                        "The healthy node 'endpoint one' should have served 
the request: " + i,
+                        basePathToSucceed,
+                        response.server);
+                checkSynchonousResponseContent(response, qValue);
+            }
+        }
     }
-  }
 
-  public static class MockHttp2SolrClient extends Http2SolrClient {
+    private void checkSynchonousResponseContent(LBSolrClient.Rsp response, 
String qValue) {
+        assertEquals("There should be one element in the respnse.", 1, 
response.getResponse().size());
+        assertEquals(
+                "The response key 'response' should echo the query.",
+                qValue,
+                response.getResponse().get("response"));
+    }
+
+    @Test
+    public void testAsyncWithFailures() {
+
+        // This demonstrates that the failing endpoint always gets retried, 
and it is up to the user
+        // to remove any failing nodes if desired.
 
-    public List<SolrRequest<?>> lastSolrRequests = new ArrayList<>();
+        LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
+        LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
+        List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
 
-    public List<String> lastBasePaths = new ArrayList<>();
+        Http2SolrClient.Builder b =
+                new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
+        ;
+        try (MockHttpSolrClient client = new 
MockHttpSolrClient("http://base.url";, b);
+             LBHttp2SolrClient testClient = new 
LBHttp2SolrClient.Builder(client, ep1, ep2).build()) {
 
-    public List<String> lastCollections = new ArrayList<>();
+            for (int j = 0; j < 2; j++) {
+                // first time Endpoint One will return error code 500.
+                // second time Endpoint One will be healthy
 
-    public String basePathToFail = null;
+                String basePathToSucceed;
+                if (j == 0) {
+                    client.basePathToFail = ep1.getBaseUrl();
+                    basePathToSucceed = ep2.getBaseUrl();
+                } else {
+                    client.basePathToFail = ep2.getBaseUrl();
+                    basePathToSucceed = ep1.getBaseUrl();
+                }
 
-    protected MockHttp2SolrClient(String serverBaseUrl, Builder builder) {
-      // TODO: Consider creating an interface for Http*SolrClient
-      // so mocks can Implement, not Extend, and not actually need to
-      // build an (unused) client
-      super(serverBaseUrl, builder);
+                for (int i = 0; i < 10; i++) {
+                    // i: we'll try 10 times to see if it behaves the same 
every time.
+
+                    QueryRequest queryRequest = new QueryRequest(new 
MapSolrParams(Map.of("q", "" + i)));
+                    LBSolrClient.Req req = new LBSolrClient.Req(queryRequest, 
endpointList);
+                    String iterMessage = "iter j/i " + j + "/" + i;
+                    try {
+                        testClient.requestAsync(req).get(1, TimeUnit.MINUTES);
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        fail("interrupted");
+                    } catch (TimeoutException | ExecutionException e) {
+                        fail(iterMessage + " Response ended in failure: " + e);
+                    }
+                    if (i == 0) {
+                        // When j=0, "endpoint one" fails.
+                        // The first time around (i) it tries the first, then 
the second.
+                        //
+                        // With j=0 and i>0, it only tries "endpoint two".
+                        //
+                        // When j=1 and i=0, "endpoint two" starts failing.
+                        // So it tries both it and "endpoint one"
+                        //
+                        // With j=1 and i>0, it only tries "endpoint one".
+                        assertEquals(iterMessage, 2, 
client.lastBasePaths.size());
+
+                        String failedBasePath = client.lastBasePaths.remove(0);
+                        assertEquals(iterMessage, client.basePathToFail, 
failedBasePath);
+                    } else {
+                        // The first endpoint does not give the exception, it 
doesn't retry.
+                        assertEquals(iterMessage, 1, 
client.lastBasePaths.size());
+                    }
+                    String successBasePath = client.lastBasePaths.remove(0);
+                    assertEquals(iterMessage, basePathToSucceed, 
successBasePath);
+                }
+            }
+        }
     }
 
-    @Override
-    public CompletableFuture<NamedList<Object>> requestAsync(
-        final SolrRequest<?> solrRequest, String collection) {
-      CompletableFuture<NamedList<Object>> cf = new CompletableFuture<>();
-      lastSolrRequests.add(solrRequest);
-      lastBasePaths.add(solrRequest.getBasePath());
-      lastCollections.add(collection);
-      if (solrRequest.getBasePath().equals(basePathToFail)) {
-        cf.completeExceptionally(
-            new SolrException(SolrException.ErrorCode.SERVER_ERROR, "We should 
retry this."));
-      } else {
-        cf.complete(generateResponse(solrRequest));
-      }
-      return cf;
+    @Test
+    public void testAsync() {
+        LBSolrClient.Endpoint ep1 = new 
LBSolrClient.Endpoint("http://endpoint.one";);
+        LBSolrClient.Endpoint ep2 = new 
LBSolrClient.Endpoint("http://endpoint.two";);
+        List<LBSolrClient.Endpoint> endpointList = List.of(ep1, ep2);
+
+        Http2SolrClient.Builder b =
+                new 
Http2SolrClient.Builder("http://base.url";).withConnectionTimeout(10, 
TimeUnit.SECONDS);
+        try (MockHttpSolrClient client = new 
MockHttpSolrClient("http://base.url";, b);
+             LBHttp2SolrClient testClient = new 
LBHttp2SolrClient.Builder(client, ep1, ep2).build()) {
+
+            int limit = 10; // For simplicity use an even limit
+            List<CompletableFuture<LBSolrClient.Rsp>> responses = new 
ArrayList<>();
+
+            for (int i = 0; i < limit; i++) {
+                QueryRequest queryRequest = new QueryRequest(new 
MapSolrParams(Map.of("q", "" + i)));
+                LBSolrClient.Req req = new LBSolrClient.Req(queryRequest, 
endpointList);
+                responses.add(testClient.requestAsync(req));
+            }
+
+            QueryRequest[] queryRequests = new QueryRequest[limit];
+            int numEndpointOne = 0;
+            int numEndpointTwo = 0;
+            for (int i = 0; i < limit; i++) {
+                SolrRequest<?> lastSolrReq = client.lastSolrRequests.get(i);
+                assertTrue(lastSolrReq instanceof QueryRequest);
+                QueryRequest lastQueryReq = (QueryRequest) lastSolrReq;
+                int index = 
Integer.parseInt(lastQueryReq.getParams().get("q"));
+                assertNull("Found same request twice: " + index, 
queryRequests[index]);
+                queryRequests[index] = lastQueryReq;
+                if (lastQueryReq.getBasePath().equals(ep1.toString())) {
+                    numEndpointOne++;
+                } else if (lastQueryReq.getBasePath().equals(ep2.toString())) {
+                    numEndpointTwo++;
+                }
+
+                LBSolrClient.Rsp lastRsp = null;
+                try {
+                    lastRsp = responses.get(index).get();
+                } catch (InterruptedException ie) {
+                    Thread.currentThread().interrupt();
+                    fail("interrupted");
+                } catch (ExecutionException ee) {
+                    fail("Response " + index + " ended in failure: " + ee);
+                }
+                NamedList<Object> lastResponse = lastRsp.getResponse();
+
+                // The Mock will return {"response": index}.
+                assertEquals("" + index, lastResponse.get("response"));
+            }
+
+            // It is the user's responsibility to shuffle the endpoints when 
using
+            // async.  LB Http Solr Client will always try the passed-in 
endpoints
+            // in order.  In this case, endpoint 1 gets all the requests!
+            assertEquals(limit, numEndpointOne);
+            assertEquals(0, numEndpointTwo);
+
+            assertEquals(limit, client.lastSolrRequests.size());
+            assertEquals(limit, client.lastCollections.size());
+        }
     }
 
-    private NamedList<Object> generateResponse(SolrRequest<?> solrRequest) {
-      String id = solrRequest.getParams().get("q");
-      return new NamedList<>(Collections.singletonMap("response", id));
+    public static class MockHttpSolrClient extends Http2SolrClient {
+
+        public List<SolrRequest<?>> lastSolrRequests = new ArrayList<>();
+
+        public List<String> lastBasePaths = new ArrayList<>();
+
+        public List<String> lastCollections = new ArrayList<>();
+
+        public String basePathToFail = null;
+
+        protected MockHttpSolrClient(String serverBaseUrl, Builder builder) {
+            // TODO: Consider creating an interface for Http*SolrClient
+            // so mocks can Implement, not Extend, and not actually need to
+            // build an (unused) client
+            super(serverBaseUrl, builder);
+        }
+
+        @Override
+        public NamedList<Object> request(final SolrRequest<?> request, String 
collection)
+                throws SolrServerException, IOException {
+            lastSolrRequests.add(request);
+            lastBasePaths.add(request.getBasePath());
+            lastCollections.add(collection);
+            if (request.getBasePath().equals(basePathToFail)) {
+                throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, 
"We should retry this.");
+            }
+            return generateResponse(request);
+        }
+
+        @Override
+        public CompletableFuture<NamedList<Object>> requestAsync(
+                final SolrRequest<?> solrRequest, String collection) {
+            CompletableFuture<NamedList<Object>> cf = new 
CompletableFuture<>();
+            lastSolrRequests.add(solrRequest);
+            lastBasePaths.add(solrRequest.getBasePath());
+            lastCollections.add(collection);
+            if (solrRequest.getBasePath().equals(basePathToFail)) {
+                cf.completeExceptionally(
+                        new 
SolrException(SolrException.ErrorCode.SERVER_ERROR, "We should retry this."));
+            } else {
+                cf.complete(generateResponse(solrRequest));
+            }
+            return cf;
+        }
+
+        private NamedList<Object> generateResponse(SolrRequest<?> solrRequest) 
{
+            String id = solrRequest.getParams().get("q");
+            return new NamedList<>(Collections.singletonMap("response", id));
+        }
     }
-  }
 }

Reply via email to