diff --git a/common/src/main/java/org/apache/seata/common/metadata/Node.java b/common/src/main/java/org/apache/seata/common/metadata/Node.java index ddb802713cb..18586b0efa7 100644 --- a/common/src/main/java/org/apache/seata/common/metadata/Node.java +++ b/common/src/main/java/org/apache/seata/common/metadata/Node.java @@ -16,6 +16,7 @@ */ package org.apache.seata.common.metadata; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.seata.common.exception.ParseEndpointException; @@ -99,6 +100,32 @@ public void setVersion(String version) { this.version = version; } + @JsonIgnore + public boolean isHttp2Supported() { + String baseVersion = "2.6.0"; + + if (version == null || version.isEmpty()) { + return false; + } + + String[] current = version.split("\\."); + String[] base = baseVersion.split("\\."); + + int len = Math.max(current.length, base.length); + for (int i = 0; i < len; i++) { + int cur = i < current.length ? Integer.parseInt(current[i]) : 0; + int bas = i < base.length ? Integer.parseInt(base[i]) : 0; + + if (cur > bas) { + return true; + } + if (cur < bas) { + return false; + } + } + return true; + } + public Endpoint getInternal() { return internal; } diff --git a/common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java b/common/src/main/java/org/apache/seata/common/util/Http2ClientUtil.java similarity index 95% rename from common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java rename to common/src/main/java/org/apache/seata/common/util/Http2ClientUtil.java index bcf95a00e55..efb5c3a419e 100644 --- a/common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java +++ b/common/src/main/java/org/apache/seata/common/util/Http2ClientUtil.java @@ -35,9 +35,9 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -public class Http5ClientUtil { +public class Http2ClientUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(Http5ClientUtil.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Http2ClientUtil.class); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -50,7 +50,7 @@ public class Http5ClientUtil { public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json"); public static final MediaType MEDIA_TYPE_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded"); - public static void doPostHttp( + public static void doPost( String url, Map params, Map headers, HttpCallback callback) { try { Headers.Builder headerBuilder = new Headers.Builder(); @@ -75,8 +75,7 @@ public static void doPostHttp( } } - public static void doPostHttp( - String url, String body, Map headers, HttpCallback callback) { + public static void doPost(String url, String body, Map headers, HttpCallback callback) { Headers.Builder headerBuilder = new Headers.Builder(); if (headers != null) { headers.forEach(headerBuilder::add); @@ -93,7 +92,7 @@ public static void doPostHttp( executeAsync(HTTP_CLIENT, request, callback); } - public static void doGetHttp( + public static void doGet( String url, Map headers, final HttpCallback callback, int timeout) { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(timeout, TimeUnit.SECONDS) diff --git a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java b/common/src/test/java/org/apache/seata/common/util/Http2ClientUtilTest.java similarity index 86% rename from common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java rename to common/src/test/java/org/apache/seata/common/util/Http2ClientUtilTest.java index 9b550067e75..06b46f3f583 100644 --- a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java +++ b/common/src/test/java/org/apache/seata/common/util/Http2ClientUtilTest.java @@ -31,10 +31,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -class Http5ClientUtilTest { +class Http2ClientUtilTest { @Test - void testDoPostHttp_param_onSuccess() throws Exception { + void testDoPost_param_onSuccess() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -62,12 +62,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("https://www.apache.org/", params, headers, callback); + Http2ClientUtil.doPost("https://www.apache.org/", params, headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoPostHttp_param_onFailure() throws Exception { + void testDoPost_param_onFailure() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -94,12 +94,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("http://localhost:9999/invalid", params, headers, callback); + Http2ClientUtil.doPost("http://localhost:9999/invalid", params, headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoPostHttp_body_onSuccess() throws Exception { + void testDoPost_body_onSuccess() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -124,12 +124,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("https://www.apache.org/", "{\"key\":\"value\"}", headers, callback); + Http2ClientUtil.doPost("https://www.apache.org/", "{\"key\":\"value\"}", headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoPostHttp_body_onFailure() throws Exception { + void testDoPost_body_onFailure() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -153,12 +153,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("http://localhost:9999/invalid", "{\"key\":\"value\"}", headers, callback); + Http2ClientUtil.doPost("http://localhost:9999/invalid", "{\"key\":\"value\"}", headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoPostHttp_param_onSuccess_forceHttp1() throws Exception { + void testDoPostHttp_param_onSuccess_force1() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -186,12 +186,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("http://httpbin.org/post", params, headers, callback); + Http2ClientUtil.doPost("http://httpbin.org/post", params, headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoGetHttp_onSuccess() throws Exception { + void testDoGet_onSuccess() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -216,12 +216,12 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Accept", "application/json"); - Http5ClientUtil.doGetHttp("https://www.apache.org/", headers, callback, 1); + Http2ClientUtil.doGet("https://www.apache.org/", headers, callback, 1); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test - void testDoPostHttp_body_onSuccess_forceHttp1() throws Exception { + void testDoPostHttp_body_onSuccess_force1() throws Exception { CountDownLatch latch = new CountDownLatch(1); HttpCallback callback = new HttpCallback() { @@ -246,7 +246,7 @@ public void onCancelled() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); - Http5ClientUtil.doPostHttp("http://httpbin.org/post", "{\"key\":\"value\"}", headers, callback); + Http2ClientUtil.doPost("http://httpbin.org/post", "{\"key\":\"value\"}", headers, callback); assertTrue(latch.await(10, TimeUnit.SECONDS)); } } diff --git a/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java b/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java index ded156e6c62..97fe474f93d 100644 --- a/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java +++ b/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.Response; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; @@ -30,11 +31,13 @@ import org.apache.seata.common.exception.NotSupportYetException; import org.apache.seata.common.exception.ParseEndpointException; import org.apache.seata.common.exception.RetryableException; +import org.apache.seata.common.executor.HttpCallback; import org.apache.seata.common.metadata.Metadata; import org.apache.seata.common.metadata.MetadataResponse; import org.apache.seata.common.metadata.Node; import org.apache.seata.common.thread.NamedThreadFactory; import org.apache.seata.common.util.CollectionUtils; +import org.apache.seata.common.util.Http2ClientUtil; import org.apache.seata.common.util.HttpClientUtil; import org.apache.seata.common.util.NetUtil; import org.apache.seata.common.util.StringUtils; @@ -55,6 +58,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; @@ -63,11 +67,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * The type File registry service. - * */ public class RaftRegistryServiceImpl implements RegistryService { @@ -221,46 +223,59 @@ protected static void startQueryMetadata() { } } - private static String queryHttpAddress(String clusterName, String group) { + private static Node selectNodeForHttpAddress(String clusterName, String group) { List nodeList = METADATA.getNodes(clusterName, group); - List addressList = null; - Stream stream = null; + if (CollectionUtils.isNotEmpty(nodeList)) { List inetSocketAddresses = ALIVE_NODES.get(CURRENT_TRANSACTION_SERVICE_GROUP); + if (CollectionUtils.isEmpty(inetSocketAddresses)) { - addressList = nodeList.stream() - .map(RaftRegistryServiceImpl::selectControlEndpointStr) - .collect(Collectors.toList()); - } else { - stream = inetSocketAddresses.stream(); + return nodeList.get(ThreadLocalRandom.current().nextInt(nodeList.size())); } - } else { - stream = INIT_ADDRESSES.get(clusterName).stream(); - } - if (addressList != null) { - return addressList.get(ThreadLocalRandom.current().nextInt(addressList.size())); - } else { + Map map = new HashMap<>(); - if (CollectionUtils.isNotEmpty(nodeList)) { - for (Node node : nodeList) { - InetSocketAddress inetSocketAddress = selectTransactionEndpoint(node); - map.put(inetSocketAddress.getHostString() + IP_PORT_SPLIT_CHAR + inetSocketAddress.getPort(), node); - } + for (Node node : nodeList) { + InetSocketAddress inetSocketAddress = selectTransactionEndpoint(node); + map.put(inetSocketAddress.getHostString() + IP_PORT_SPLIT_CHAR + inetSocketAddress.getPort(), node); } - addressList = stream.map(inetSocketAddress -> { - String host = NetUtil.toStringHost(inetSocketAddress); - Node node = map.get(host + IP_PORT_SPLIT_CHAR + inetSocketAddress.getPort()); - InetSocketAddress controlEndpoint = null; - if (node != null) { - controlEndpoint = selectControlEndpoint(node); - } - return host - + IP_PORT_SPLIT_CHAR - + (controlEndpoint != null ? controlEndpoint.getPort() : inetSocketAddress.getPort()); - }) + + List aliveNodes = inetSocketAddresses.stream() + .map(addr -> map.get(NetUtil.toStringHost(addr) + IP_PORT_SPLIT_CHAR + addr.getPort())) + .filter(Objects::nonNull) .collect(Collectors.toList()); - return addressList.get(ThreadLocalRandom.current().nextInt(addressList.size())); + + if (!aliveNodes.isEmpty()) { + return aliveNodes.get(ThreadLocalRandom.current().nextInt(aliveNodes.size())); + } + } else { + List initAddresses = INIT_ADDRESSES.get(clusterName); + if (CollectionUtils.isNotEmpty(initAddresses)) { + + return null; + } + } + return null; + } + + private static String queryHttpAddress(String clusterName, Node selectedNode) { + String address = extractHttpAddressFromNode(selectedNode); + if (address != null) { + return address; + } + List initAddresses = INIT_ADDRESSES.get(clusterName); + if (CollectionUtils.isNotEmpty(initAddresses)) { + InetSocketAddress inetSocketAddress = + initAddresses.get(ThreadLocalRandom.current().nextInt(initAddresses.size())); + return NetUtil.toStringAddress(inetSocketAddress); + } + return null; + } + + private static String extractHttpAddressFromNode(Node node) { + if (node == null) { + return null; } + return selectControlEndpointStr(node); } private static String getRaftAddrFileKey() { @@ -418,36 +433,109 @@ private static boolean watch() throws RetryableException { Map groupTerms = METADATA.getClusterTerm(clusterName); groupTerms.forEach((k, v) -> param.put(k, String.valueOf(v))); for (String group : groupTerms.keySet()) { - String tcAddress = queryHttpAddress(clusterName, group); + Node selectedNode = selectNodeForHttpAddress(clusterName, group); + String tcAddress = queryHttpAddress(clusterName, selectedNode); + if (isTokenExpired()) { - refreshToken(tcAddress); + refreshToken(clusterName, selectedNode); } if (StringUtils.isNotBlank(jwtToken)) { header.put(AUTHORIZATION_HEADER, jwtToken); } - try (CloseableHttpResponse response = - HttpClientUtil.doPost("http://" + tcAddress + "/metadata/v1/watch", param, header, 30000)) { - if (response != null) { - StatusLine statusLine = response.getStatusLine(); - if (statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - if (StringUtils.isNotBlank(USERNAME) && StringUtils.isNotBlank(PASSWORD)) { - throw new RetryableException("Authentication failed!"); - } else { - throw new AuthenticationFailedException( - "Authentication failed! you should configure the correct username and password."); - } + + ResponseProcessor processor = (responseBody, error) -> { + if (error != null) { + LOGGER.error("Watch request failed: {}", error.getMessage(), error); + } else if (StringUtils.isNotBlank(responseBody)) { + try { + processWatchResponse(responseBody); + } catch (Exception e) { + LOGGER.error("Error processing watch response: {}", e.getMessage(), e); } - return statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_OK; } - } catch (IOException e) { - LOGGER.error("watch cluster node: {}, fail: {}", tcAddress, e.getMessage()); - throw new RetryableException(e.getMessage(), e); + }; + + if (selectedNode != null && selectedNode.isHttp2Supported()) { + executeHttp2WatchRequest(tcAddress, param, header, processor); + } else { + executeHttpWatchRequest(tcAddress, param, header, processor); } - break; + return true; } return false; } + private static void executeHttpWatchRequest( + String tcAddress, Map param, Map header, ResponseProcessor processor) { + try (CloseableHttpResponse response = + HttpClientUtil.doPost("http://" + tcAddress + "/metadata/v1/watch", param, header, 30000)) { + if (response != null) { + StatusLine statusLine = response.getStatusLine(); + if (statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + processor.process(null, new RetryableException("Authentication failed!")); + } else if (statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_OK) { + String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + processor.process(responseBody, null); + } else { + processor.process( + null, + new RetryableException("Invalid response status: " + + (statusLine != null ? statusLine.getStatusCode() : "unknown"))); + } + } else { + processor.process(null, new RetryableException("Null response")); + } + } catch (Exception e) { + processor.process(null, new RetryableException(e.getMessage(), e)); + } + } + + private static void executeHttp2WatchRequest( + String tcAddress, Map param, Map header, ResponseProcessor processor) { + Http2ClientUtil.doPost( + "http://" + tcAddress + "/metadata/v1/watch", param, header, new HttpCallback() { + @Override + public void onSuccess(Response response) { + try { + String responseBody = response.body().string(); + processor.process(responseBody, null); + } catch (IOException e) { + processor.process(null, e); + } + } + + @Override + public void onFailure(Throwable e) { + processor.process(null, e); + } + + @Override + public void onCancelled() { + processor.process(null, new RetryableException("Request cancelled")); + } + }); + } + + private static void processWatchResponse(String responseBody) { + try { + JsonNode jsonNode = OBJECT_MAPPER.readTree(responseBody); + boolean success = jsonNode.path("success").asBoolean(false); + if (success) { + LOGGER.info("Watch request successful"); + } else { + String message = jsonNode.path("message").asText("Unknown error"); + LOGGER.warn("Watch request failed: {}", message); + } + } catch (JsonProcessingException e) { + LOGGER.error("Failed to parse watch response: {}", e.getMessage(), e); + } + } + + @FunctionalInterface + private interface ResponseProcessor { + void process(String responseBody, Throwable error); + } + @Override public List refreshAliveLookup( String transactionServiceGroup, List aliveAddress) { @@ -485,11 +573,18 @@ private static void acquireClusterMetaDataByClusterName(String clusterName) { } private static void acquireClusterMetaData(String clusterName, String group) throws RetryableException { - String tcAddress = queryHttpAddress(clusterName, group); + Node selectedNode = selectNodeForHttpAddress(clusterName, group); + + if (selectedNode == null) { + LOGGER.warn("No available node found for cluster: {}, group: {}", clusterName, group); + return; + } + + String tcAddress = queryHttpAddress(clusterName, selectedNode); Map header = new HashMap<>(); header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); if (isTokenExpired()) { - refreshToken(tcAddress); + refreshToken(clusterName, selectedNode); } if (StringUtils.isNotBlank(jwtToken)) { header.put(AUTHORIZATION_HEADER, jwtToken); @@ -497,6 +592,40 @@ private static void acquireClusterMetaData(String clusterName, String group) thr if (StringUtils.isNotBlank(tcAddress)) { Map param = new HashMap<>(); param.put("group", group); + + if (selectedNode.isHttp2Supported()) { + Http2ClientUtil.doGet( + "http://" + tcAddress + "/metadata/v1/cluster", + header, + new HttpCallback() { + @Override + public void onSuccess(Response result) { + try { + String responseBody = result.body().string(); + if (StringUtils.isNotBlank(responseBody)) { + MetadataResponse metadataResponse = + OBJECT_MAPPER.readValue(responseBody, MetadataResponse.class); + METADATA.refreshMetadata(clusterName, metadataResponse); + LOGGER.debug("Metadata refreshed via HTTP/2 for cluster: {}", clusterName); + } + } catch (Exception e) { + LOGGER.error("Error processing metadata response: {}", e.getMessage(), e); + } + } + + @Override + public void onFailure(Throwable t) { + LOGGER.error("Metadata request failed: {}", t.getMessage(), t); + } + + @Override + public void onCancelled() { + LOGGER.warn("Metadata request was cancelled"); + } + }, + 1000); + return; + } String response = null; try (CloseableHttpResponse httpResponse = HttpClientUtil.doGet("http://" + tcAddress + "/metadata/v1/cluster", param, header, 1000)) { @@ -506,7 +635,7 @@ private static void acquireClusterMetaData(String clusterName, String group) thr response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); } else if (statusCode == HttpStatus.SC_UNAUTHORIZED) { if (StringUtils.isNotBlank(USERNAME) && StringUtils.isNotBlank(PASSWORD)) { - refreshToken(tcAddress); + refreshToken(tcAddress, selectedNode); throw new RetryableException("Token refreshed, retrying request."); } else { throw new AuthenticationFailedException( @@ -532,22 +661,71 @@ private static void acquireClusterMetaData(String clusterName, String group) thr } } - private static void refreshToken(String tcAddress) throws RetryableException { + private static void refreshToken(String clusterName, Node selectedNode) throws RetryableException { // if username and password is not in config , return if (StringUtils.isBlank(USERNAME) || StringUtils.isBlank(PASSWORD)) { return; } + String tcAddress = queryHttpAddress(clusterName, selectedNode); // get token and set it in cache Map param = new HashMap<>(); param.put(PRO_USERNAME_KEY, USERNAME); param.put(PRO_PASSWORD_KEY, PASSWORD); Map header = new HashMap<>(); header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); + String response = null; + + requestJwtToken(selectedNode, tcAddress, param, header); + } + + private static void requestJwtToken( + Node selectedNode, String tcAddress, Map param, Map header) + throws RetryableException { + + if (selectedNode == null) { + LOGGER.warn("No available node found for token request."); + return; + } + if (selectedNode.isHttp2Supported()) { + Http2ClientUtil.doPost( + "http://" + tcAddress + "/api/v1/auth/login", param, header, new HttpCallback() { + @Override + public void onSuccess(Response result) { + try { + String responseBody = result.body().string(); + JsonNode jsonNode = OBJECT_MAPPER.readTree(responseBody); + String codeStatus = jsonNode.get("code").asText(); + if (StringUtils.equals(codeStatus, "200")) { + jwtToken = jsonNode.get("data").asText(); + tokenTimeStamp = System.currentTimeMillis(); + LOGGER.info("JWT token refreshed successfully via HTTP/2"); + } else { + LOGGER.error("Authentication failed with code: {}", codeStatus); + } + } catch (Exception e) { + LOGGER.error("Error processing JWT token response: {}", e.getMessage(), e); + } + } + + @Override + public void onFailure(Throwable t) { + LOGGER.error("JWT token request failed: {}", t.getMessage(), t); + } + + @Override + public void onCancelled() { + LOGGER.warn("JWT token request was cancelled"); + } + }); + return; + } + String response = null; try (CloseableHttpResponse httpResponse = HttpClientUtil.doPost("http://" + tcAddress + "/api/v1/auth/login", param, header, 1000)) { if (httpResponse != null) { - if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + if (httpResponse.getStatusLine() != null + && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); JsonNode jsonNode = OBJECT_MAPPER.readTree(response); String codeStatus = jsonNode.get("code").asText(); @@ -594,7 +772,7 @@ public List lookup(String key) throws Exception { INIT_ADDRESSES.put(clusterName, list); // init jwt token try { - refreshToken(queryHttpAddress(clusterName, key)); + refreshToken(clusterName, selectNodeForHttpAddress(clusterName, key)); } catch (Exception e) { throw new RuntimeException("Init fetch token failed!", e); } diff --git a/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java b/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java index 90b9f76a0b8..7889af5713c 100644 --- a/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java +++ b/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java @@ -73,7 +73,6 @@ public void testLoginFailed() throws IOException, NoSuchMethodException { "{\"code\":\"401\",\"message\":\"Login failed\",\"data\":\"" + jwtToken + "\",\"success\":false}"; try (MockedStatic mockedStatic = Mockito.mockStatic(HttpClientUtil.class)) { - CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class); StatusLine mockStatusLine = mock(StatusLine.class); @@ -84,18 +83,15 @@ public void testLoginFailed() throws IOException, NoSuchMethodException { when(HttpClientUtil.doPost(any(String.class), any(Map.class), any(Map.class), any(int.class))) .thenReturn(mockResponse); - // Use reflection to access and invoke the private method - Method refreshTokenMethod = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class); + Method refreshTokenMethod = + RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class, Node.class); refreshTokenMethod.setAccessible(true); - assertThrows( - Exception.class, - () -> refreshTokenMethod.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092")); + + Node mockNode = mock(Node.class); + assertThrows(Exception.class, () -> refreshTokenMethod.invoke(null, "127.0.0.1:8092", mockNode)); } } - /** - * test whether the jwtToken updated when refreshToken method invoked - */ @Test public void testRefreshTokenSuccess() throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, @@ -116,9 +112,23 @@ public void testRefreshTokenSuccess() when(HttpClientUtil.doPost(any(String.class), any(Map.class), any(Map.class), any(int.class))) .thenReturn(mockResponse); - Method refreshTokenMethod = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class); + Method refreshTokenMethod = + RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class, Node.class); refreshTokenMethod.setAccessible(true); - refreshTokenMethod.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092"); + + Node mockNode = mock(Node.class); + Map metadata = new HashMap<>(); + List> externalEndpoints = new ArrayList<>(); + LinkedHashMap externalEndpoint = new LinkedHashMap<>(); + externalEndpoint.put("host", "10.10.105.7"); + externalEndpoint.put("controlPort", 30071); + externalEndpoint.put("transactionPort", 30091); + externalEndpoints.add(externalEndpoint); + metadata.put("external", externalEndpoints); + when(mockNode.getMetadata()).thenReturn(metadata); + + refreshTokenMethod.invoke(null, "127.0.0.1:8092", mockNode); + Field jwtTokenField = RaftRegistryServiceImpl.class.getDeclaredField("jwtToken"); jwtTokenField.setAccessible(true); String jwtTokenAct = (String) jwtTokenField.get(null);