This is an automated email from the ASF dual-hosted git repository.
liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new e00098b2bf feat: add infra-etcd unit test (#6087)
e00098b2bf is described below
commit e00098b2bff36117c991ba3b7d7ac69272a34fd0
Author: shown <[email protected]>
AuthorDate: Thu Aug 7 22:32:49 2025 +0800
feat: add infra-etcd unit test (#6087)
---
.../shenyu-admin-listener-etcd/pom.xml | 4 -
.../config/properties/EtcdPropertiesTest.java | 48 -----
.../shenyu/admin/listener/etcd/EtcdClientTest.java | 93 ---------
shenyu-infra/shenyu-infra-etcd/pom.xml | 13 ++
.../infra/etcd/autoconfig/EtcdConfiguration.java | 2 +
.../infra/etcd/autoconfig/EtcdPropertiesTest.java | 53 ++++++
.../shenyu/infra/etcd/client/EtcdClientTest.java | 137 ++++++++++++++
.../shenyu/sync/data/etcd/EtcdClientTest.java | 210 ---------------------
8 files changed, 205 insertions(+), 355 deletions(-)
diff --git a/shenyu-admin-listener/shenyu-admin-listener-etcd/pom.xml
b/shenyu-admin-listener/shenyu-admin-listener-etcd/pom.xml
index ce28ded084..ce433ce7de 100644
--- a/shenyu-admin-listener/shenyu-admin-listener-etcd/pom.xml
+++ b/shenyu-admin-listener/shenyu-admin-listener-etcd/pom.xml
@@ -27,10 +27,6 @@
<artifactId>shenyu-admin-listener-etcd</artifactId>
<dependencies>
- <dependency>
- <artifactId>grpc-netty</artifactId>
- <groupId>io.grpc</groupId>
- </dependency>
<dependency>
<groupId>org.apache.shenyu</groupId>
diff --git
a/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/config/properties/EtcdPropertiesTest.java
b/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/config/properties/EtcdPropertiesTest.java
deleted file mode 100644
index d4b62153e9..0000000000
---
a/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/config/properties/EtcdPropertiesTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shenyu.admin.config.properties;
-
-import org.apache.shenyu.infra.etcd.autoconfig.EtcdProperties;
-import org.apache.shenyu.infra.etcd.config.EtcdConfig;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test cases for {@link EtcdProperties}.
- */
-public class EtcdPropertiesTest {
-
- @Test
- public void etcdPropertiesTest() {
-
- final EtcdProperties etcdProperties = new EtcdProperties();
- etcdProperties.setEtcd(
- EtcdConfig.builder()
- .url("url")
- .sessionTimeout(0)
- .connectionTimeout(0)
- .serializer("serializer")
- .build()
- );
-
- Assertions.assertEquals(etcdProperties.getEtcd().getUrl(), "url");
- Assertions.assertEquals(etcdProperties.getEtcd().getSerializer(),
"serializer");
-
Assertions.assertEquals(etcdProperties.getEtcd().getConnectionTimeout(), 0);
- Assertions.assertEquals(etcdProperties.getEtcd().getSessionTimeout(),
0);
- }
-}
diff --git
a/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/listener/etcd/EtcdClientTest.java
b/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/listener/etcd/EtcdClientTest.java
deleted file mode 100644
index 89b275d1d8..0000000000
---
a/shenyu-admin-listener/shenyu-admin-listener-etcd/src/test/java/org/apache/shenyu/admin/listener/etcd/EtcdClientTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shenyu.admin.listener.etcd;
-
-import org.apache.shenyu.infra.etcd.client.EtcdClient;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CompletableFuture;
-import io.etcd.jetcd.ByteSequence;
-import io.etcd.jetcd.Client;
-import io.etcd.jetcd.KV;
-import io.etcd.jetcd.kv.DeleteResponse;
-import io.etcd.jetcd.kv.PutResponse;
-import io.etcd.jetcd.options.DeleteOption;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * The testCase for {@link EtcdClient}.
- */
-@ExtendWith(MockitoExtension.class)
-public class EtcdClientTest {
-
- private static final String TEST_KEY = "KEY";
-
- private static final String TEST_VALUE = "VALUE";
-
- @Mock
- private Client client;
-
- private EtcdClient etcdClient;
-
- @BeforeEach
- public void setUp() {
- KV kvClient = mock(KV.class);
- when(client.getKVClient()).thenReturn(kvClient);
- etcdClient = EtcdClient.builder().client(client).build();
- assertNotNull(etcdClient);
- }
-
- @AfterEach
- public void close() {
- etcdClient.close();
- }
-
- @Test
- public void put() {
- CompletableFuture<PutResponse> put = mock(CompletableFuture.class);
- when(client.getKVClient().put(ByteSequence.from(TEST_KEY,
StandardCharsets.UTF_8), ByteSequence.from(TEST_VALUE,
StandardCharsets.UTF_8))).thenReturn(put);
- etcdClient.put(TEST_KEY, TEST_VALUE);
- verify(client.getKVClient(), times(1)).put(any(ByteSequence.class),
any(ByteSequence.class));
- }
-
- @Test
- public void delete() {
- CompletableFuture<DeleteResponse> delete =
mock(CompletableFuture.class);
- when(client.getKVClient().delete(ByteSequence.from(TEST_KEY,
StandardCharsets.UTF_8))).thenReturn(delete);
- etcdClient.delete(TEST_KEY);
- verify(client.getKVClient(), times(1)).delete(any(ByteSequence.class));
- }
-
- @Test
- public void deleteEtcdPathRecursive() {
- when(client.getKVClient().delete(any(ByteSequence.class),
any(DeleteOption.class))).thenReturn(mock(CompletableFuture.class));
- etcdClient.deleteEtcdPathRecursive(TEST_KEY);
- verify(client.getKVClient(), times(1)).delete(any(ByteSequence.class),
any(DeleteOption.class));
- }
-}
diff --git a/shenyu-infra/shenyu-infra-etcd/pom.xml
b/shenyu-infra/shenyu-infra-etcd/pom.xml
index 03ce9011eb..96f2f578a7 100644
--- a/shenyu-infra/shenyu-infra-etcd/pom.xml
+++ b/shenyu-infra/shenyu-infra-etcd/pom.xml
@@ -70,6 +70,19 @@
<version>${grpc.version}</version>
</dependency>
+ <dependency>
+ <artifactId>grpc-netty</artifactId>
+ <groupId>io.grpc</groupId>
+ <version>${grpc.version}</version>
+ </dependency>
+
+ <!-- Test -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
</project>
diff --git
a/shenyu-infra/shenyu-infra-etcd/src/main/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdConfiguration.java
b/shenyu-infra/shenyu-infra-etcd/src/main/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdConfiguration.java
index c01c782cc6..fb1e9d7d06 100644
---
a/shenyu-infra/shenyu-infra-etcd/src/main/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdConfiguration.java
+++
b/shenyu-infra/shenyu-infra-etcd/src/main/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdConfiguration.java
@@ -22,6 +22,7 @@ import org.apache.shenyu.infra.etcd.client.EtcdClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import
org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -41,6 +42,7 @@ public class EtcdConfiguration {
* @return Etcd Client
*/
@Bean
+ @ConditionalOnMissingBean
public EtcdClient etcdClient(final EtcdProperties etcdProperties) {
log.info("Initializing Etcd Client with URL: {}",
etcdProperties.getEtcd().getUrl());
diff --git
a/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdPropertiesTest.java
b/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdPropertiesTest.java
new file mode 100644
index 0000000000..c2899bf056
--- /dev/null
+++
b/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/autoconfig/EtcdPropertiesTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.infra.etcd.autoconfig;
+
+import org.apache.shenyu.infra.etcd.config.EtcdConfig;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class EtcdPropertiesTest {
+
+ @Test
+ public void testDefaultEtcdConfigValues() {
+ EtcdProperties etcdProperties = new EtcdProperties();
+ EtcdConfig etcdConfig = etcdProperties.getEtcd();
+
+ assertNotNull(etcdConfig, "EtcdConfig should not be null");
+ assertEquals(30 * 1000, etcdConfig.getConnectionTimeout(), "Default
connection timeout should be 30 seconds");
+ assertEquals(30 * 1000, etcdConfig.getSessionTimeout(), "Default
session timeout should be 30 seconds");
+ }
+
+ @Test
+ public void testSetEtcdConfig() {
+ EtcdProperties etcdProperties = new EtcdProperties();
+ EtcdConfig customConfig = EtcdConfig.builder()
+ .connectionTimeout(60 * 1000)
+ .sessionTimeout(60 * 1000)
+ .build();
+
+ etcdProperties.setEtcd(customConfig);
+ EtcdConfig etcdConfig = etcdProperties.getEtcd();
+
+ assertNotNull(etcdConfig, "EtcdConfig should not be null after
setting");
+ assertEquals(60 * 1000, etcdConfig.getConnectionTimeout(), "Connection
timeout should be updated to 60 seconds");
+ assertEquals(60 * 1000, etcdConfig.getSessionTimeout(), "Session
timeout should be updated to 60 seconds");
+ }
+}
diff --git
a/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/client/EtcdClientTest.java
b/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/client/EtcdClientTest.java
new file mode 100644
index 0000000000..bb5e3eb252
--- /dev/null
+++
b/shenyu-infra/shenyu-infra-etcd/src/test/java/org/apache/shenyu/infra/etcd/client/EtcdClientTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.infra.etcd.client;
+
+import io.etcd.jetcd.Client;
+import io.etcd.jetcd.ClientBuilder;
+import io.etcd.jetcd.KV;
+import io.etcd.jetcd.Lease;
+import io.etcd.jetcd.kv.PutResponse;
+import io.etcd.jetcd.lease.LeaseGrantResponse;
+import io.etcd.jetcd.lease.LeaseKeepAliveResponse;
+import io.grpc.stub.StreamObserver;
+import org.apache.shenyu.common.exception.ShenyuException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class EtcdClientTest {
+
+ @Test
+ public void etcdClientTest() {
+ try (MockedStatic<Client> clientMockedStatic =
mockStatic(Client.class)) {
+ final ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ clientMockedStatic.when(Client::builder).thenReturn(clientBuilder);
+
when(clientBuilder.endpoints(anyString())).thenReturn(clientBuilder);
+ final Client client = mock(Client.class);
+
when(clientBuilder.endpoints(anyString()).build()).thenReturn(client);
+ final Lease lease = mock(Lease.class);
+ when(client.getLeaseClient()).thenReturn(lease);
+ final CompletableFuture<LeaseGrantResponse> completableFuture =
mock(CompletableFuture.class);
+ final LeaseGrantResponse leaseGrantResponse =
mock(LeaseGrantResponse.class);
+
+
when(client.getLeaseClient().grant(anyLong())).thenReturn(completableFuture);
+ when(completableFuture.get()).thenReturn(leaseGrantResponse);
+ Assertions.assertDoesNotThrow(() ->
EtcdClient.builder().client(Client.builder().endpoints("url").build())).ttl(60L).timeout(3000L).build();
+
+ List<StreamObserver<LeaseKeepAliveResponse>> observerList = new
ArrayList<>();
+ doAnswer(invocation -> {
+ observerList.add(invocation.getArgument(1));
+ return lease;
+ }).when(lease).keepAlive(anyLong(), any());
+ Assertions.assertDoesNotThrow(() ->
EtcdClient.builder().client(Client.builder().endpoints("url").build())).ttl(60L).timeout(3000L).build();
+ final LeaseKeepAliveResponse leaseKeepAliveResponse =
mock(LeaseKeepAliveResponse.class);
+ observerList.forEach(streamObserver -> {
+ streamObserver.onCompleted();
+ streamObserver.onError(new ShenyuException("test"));
+ streamObserver.onNext(leaseKeepAliveResponse);
+ });
+
+ doThrow(new
InterruptedException("error")).when(completableFuture).get();
+ Assertions.assertDoesNotThrow(() ->
EtcdClient.builder().client(Client.builder().endpoints("url").build())).ttl(60L).timeout(3000L).build();
+ } catch (Exception e) {
+ throw new ShenyuException(e.getCause());
+ }
+ }
+
+ @Test
+ public void closeTest() {
+ try (MockedStatic<Client> clientMockedStatic =
mockStatic(Client.class)) {
+ this.mockEtcd(clientMockedStatic);
+ final EtcdClient etcdClient =
EtcdClient.builder().client(Client.builder().endpoints("url").build()).ttl(60L).timeout(3000L).build();
+ etcdClient.close();
+ } catch (Exception e) {
+ throw new ShenyuException(e.getCause());
+ }
+ }
+
+ @Test
+ public void putEphemeralTest() {
+ try (MockedStatic<Client> clientMockedStatic =
mockStatic(Client.class)) {
+ final Client client = this.mockEtcd(clientMockedStatic);
+ final KV mockKV = mock(KV.class);
+ when(client.getKVClient()).thenReturn(mockKV);
+ final CompletableFuture<PutResponse> completableFuture =
mock(CompletableFuture.class);
+ when(mockKV.put(any(), any(),
any())).thenReturn(completableFuture);
+ final PutResponse putResponse = mock(PutResponse.class);
+ when(completableFuture.get(anyLong(),
any(TimeUnit.class))).thenReturn(putResponse);
+ final EtcdClient etcdClient =
EtcdClient.builder().client(Client.builder().endpoints("url").build()).ttl(60L).timeout(3000L).build();
+ etcdClient.putEphemeral("key", "value");
+
+ doThrow(new
InterruptedException("error")).when(completableFuture).get(anyLong(),
any(TimeUnit.class));
+ etcdClient.putEphemeral("key", "value");
+ } catch (Exception e) {
+ throw new ShenyuException(e.getCause());
+ }
+ }
+
+ private Client mockEtcd(final MockedStatic<Client> clientMockedStatic)
throws InterruptedException, ExecutionException {
+ final ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ clientMockedStatic.when(Client::builder).thenReturn(clientBuilder);
+ when(clientBuilder.endpoints(anyString())).thenReturn(clientBuilder);
+ final Client client = mock(Client.class);
+ when(clientBuilder.endpoints(anyString()).build()).thenReturn(client);
+ final Lease lease = mock(Lease.class);
+ when(client.getLeaseClient()).thenReturn(lease);
+ final CompletableFuture<LeaseGrantResponse> completableFuture =
mock(CompletableFuture.class);
+ final LeaseGrantResponse leaseGrantResponse =
mock(LeaseGrantResponse.class);
+
when(client.getLeaseClient().grant(anyLong())).thenReturn(completableFuture);
+ when(completableFuture.get()).thenReturn(leaseGrantResponse);
+ return client;
+ }
+
+}
diff --git
a/shenyu-sync-data-center/shenyu-sync-data-etcd/src/test/java/org/apache/shenyu/sync/data/etcd/EtcdClientTest.java
b/shenyu-sync-data-center/shenyu-sync-data-etcd/src/test/java/org/apache/shenyu/sync/data/etcd/EtcdClientTest.java
deleted file mode 100644
index 4bc647a82a..0000000000
---
a/shenyu-sync-data-center/shenyu-sync-data-etcd/src/test/java/org/apache/shenyu/sync/data/etcd/EtcdClientTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shenyu.sync.data.etcd;
-
-import com.google.protobuf.ByteString;
-import io.etcd.jetcd.ByteSequence;
-import io.etcd.jetcd.Client;
-import io.etcd.jetcd.KV;
-import io.etcd.jetcd.KeyValue;
-import io.etcd.jetcd.Watch;
-import io.etcd.jetcd.kv.GetResponse;
-import io.etcd.jetcd.options.WatchOption;
-import io.etcd.jetcd.watch.WatchEvent;
-import io.etcd.jetcd.watch.WatchResponse;
-import org.apache.shenyu.common.exception.ShenyuException;
-import org.apache.shenyu.infra.etcd.client.EtcdClient;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * test case for {@link EtcdClient}.
- */
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.LENIENT)
-public class EtcdClientTest {
-
- private static final String KEY1 = "/foo/key1";
-
- private static final String KEY2 = "/foo/key2";
-
- private static final String VALUE = "value";
-
- private static final String GET_KEY = "getKey";
-
- private static final String PREFIX = "/foo";
-
- private static final String SEPARATOR = "/";
-
- private static final String EXPECTED1 = "key1";
-
- private static final String EXPECTED2 = "key2";
-
- private static final String WATCH_DATA_CHANGE_KEY = "watchDataChange";
-
- private static final String WATCH_CHILD_CHANGE_KEY = "WatchChildChange";
-
- @InjectMocks
- private EtcdClient etcdClient;
-
- @Mock
- private Client client;
-
- @Mock
- private Watch.Watcher watcher;
-
- @BeforeEach
- public void setUp() {
- KV kv = mock(KV.class);
- final CompletableFuture<GetResponse> future =
mock(CompletableFuture.class);
- GetResponse getResponse = mock(GetResponse.class);
- List<KeyValue> keyValues = new ArrayList<>(2);
- KeyValue keyValue1 = mock(KeyValue.class);
- KeyValue keyValue2 = mock(KeyValue.class);
- keyValues.add(keyValue1);
- keyValues.add(keyValue2);
- final ByteString key1 = ByteString.copyFromUtf8(KEY1);
- final ByteString key2 = ByteString.copyFromUtf8(KEY2);
- final ByteString value1 = ByteString.copyFromUtf8(VALUE);
-
- /**
- * mock get method.
- */
- when(client.getKVClient()).thenReturn(kv);
- when(kv.get(any())).thenReturn(future);
- try {
- when(future.get()).thenReturn(getResponse);
- } catch (Exception e) {
- throw new ShenyuException(e.getCause());
- }
- when(getResponse.getKvs()).thenReturn(keyValues);
- when(keyValue1.getValue()).thenReturn(ByteSequence.from(value1));
- /**
- * mock getChildrenKeys method.
- */
- when(kv.get(any(), any())).thenReturn(future);
- when(keyValue1.getKey()).thenReturn(ByteSequence.from(key1));
- when(keyValue2.getKey()).thenReturn(ByteSequence.from(key2));
- /**
- * mock watchDataChange method.
- */
- Watch watch = mock(Watch.class);
- when(client.getWatchClient()).thenReturn(watch);
- when(watch.watch(any(ByteSequence.class),
any(Watch.Listener.class))).thenReturn(watcher);
- /**
- * mock watchChildChange method.
- */
- when(watch.watch(any(ByteSequence.class), any(WatchOption.class),
any(Watch.Listener.class))).thenReturn(watcher);
- }
-
- @Test
- public void testGet() {
- String result = etcdClient.get(GET_KEY);
- assertEquals(VALUE, result);
- }
-
- @Test
- public void testGetChildrenKeys() throws Exception {
- List<String> result = etcdClient.getChildrenKeys(PREFIX, SEPARATOR);
- List<String> expected = new ArrayList<>();
- expected.add(EXPECTED1);
- expected.add(EXPECTED2);
- assertEquals(expected, result);
- }
-
- @Test
- public void testWatchDataChange() {
- BiConsumer<String, String> updateHandler = mock(BiConsumer.class);
- Consumer<String> deleteHandler = mock(Consumer.class);
- etcdClient.watchDataChange(WATCH_DATA_CHANGE_KEY, updateHandler,
deleteHandler);
- etcdClient.watchClose(WATCH_DATA_CHANGE_KEY);
- etcdClient.watchClose("not hit");
- verify(watcher).close();
- }
-
- @Test
- public void testWatchChildChange() {
- BiConsumer<String, String> updateHandler = mock(BiConsumer.class);
- Consumer<String> deleteHandler = mock(Consumer.class);
- etcdClient.watchChildChange(WATCH_CHILD_CHANGE_KEY, updateHandler,
deleteHandler);
- etcdClient.watchClose(WATCH_CHILD_CHANGE_KEY);
- verify(watcher).close();
- }
-
- @Test
- public void testEtcdClient() throws ExecutionException,
InterruptedException {
- final Client client = mock(Client.class);
- final EtcdClient etcdClient =
EtcdClient.builder().client(client).build();
- assertDoesNotThrow(etcdClient::close);
- final KV mockKV = mock(KV.class);
- when(client.getKVClient()).thenReturn(mockKV);
- final CompletableFuture<GetResponse> future =
mock(CompletableFuture.class);
- when(mockKV.get(any(ByteSequence.class))).thenReturn(future);
- doThrow(new InterruptedException()).when(future).get();
- assertDoesNotThrow(() -> etcdClient.get("key"));
- }
-
- @Test
- public void watchTest() throws NoSuchMethodException,
InvocationTargetException, IllegalAccessException {
- BiConsumer<String, String> updateHandler = mock(BiConsumer.class);
- Consumer<String> deleteHandler = mock(Consumer.class);
- final Method watch = EtcdClient.class.getDeclaredMethod("watch",
BiConsumer.class, Consumer.class);
- watch.setAccessible(true);
- final Watch.Listener listener = (Watch.Listener)
watch.invoke(etcdClient, updateHandler, deleteHandler);
- final WatchResponse watchResponse = mock(WatchResponse.class);
- List<WatchEvent> watchEvents = new ArrayList<>(2);
- final WatchEvent watchEvent = mock(WatchEvent.class);
- watchEvents.add(watchEvent);
- when(watchResponse.getEvents()).thenReturn(watchEvents);
- final KeyValue keyValue = mock(KeyValue.class);
- when(watchEvent.getKeyValue()).thenReturn(keyValue);
- when(keyValue.getValue()).thenReturn(ByteSequence.from("value",
StandardCharsets.UTF_8));
- when(keyValue.getKey()).thenReturn(ByteSequence.from("key",
StandardCharsets.UTF_8));
- when(watchEvent.getEventType()).thenReturn(WatchEvent.EventType.PUT);
- assertDoesNotThrow(() -> listener.onNext(watchResponse));
-
when(watchEvent.getEventType()).thenReturn(WatchEvent.EventType.DELETE);
- assertDoesNotThrow(() -> listener.onNext(watchResponse));
-
when(watchEvent.getEventType()).thenReturn(WatchEvent.EventType.UNRECOGNIZED);
- assertDoesNotThrow(() -> listener.onNext(watchResponse));
- }
-
-}