Merge pull request #12165 from alibaba/summer-ospp#10374
Summer ospp#10374
This commit is contained in:
commit
d212a52bc9
@ -21,6 +21,7 @@ import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ListView;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.api.selector.AbstractSelector;
|
||||
|
||||
import java.util.List;
|
||||
@ -491,6 +492,28 @@ public interface NamingService {
|
||||
void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
|
||||
throws NacosException;
|
||||
|
||||
/**
|
||||
* Subscribe service to receive events of instances alteration.
|
||||
*
|
||||
* @param serviceName name of service
|
||||
* @param selector selector of instances
|
||||
* @param listener event listener
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
void subscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException;
|
||||
|
||||
/**
|
||||
* Subscribe service to receive events of instances alteration.
|
||||
*
|
||||
* @param serviceName name of service
|
||||
* @param groupName group of service
|
||||
* @param selector selector of instances
|
||||
* @param listener event listener
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
void subscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener)
|
||||
throws NacosException;
|
||||
|
||||
/**
|
||||
* Unsubscribe event listener of service.
|
||||
*
|
||||
@ -532,6 +555,28 @@ public interface NamingService {
|
||||
void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
|
||||
throws NacosException;
|
||||
|
||||
/**
|
||||
* Unsubscribe event listener of service.
|
||||
*
|
||||
* @param serviceName name of service
|
||||
* @param selector selector of instances
|
||||
* @param listener event listener
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
void unsubscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException;
|
||||
|
||||
/**
|
||||
* Unsubscribe event listener of service.
|
||||
*
|
||||
* @param serviceName name of service
|
||||
* @param groupName group of service
|
||||
* @param selector selector of instances
|
||||
* @param listener event listener
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
void unsubscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener)
|
||||
throws NacosException;
|
||||
|
||||
/**
|
||||
* Get all service names from server.
|
||||
*
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.api.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Naming selector context.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface NamingContext {
|
||||
|
||||
/**
|
||||
* Get service name.
|
||||
*
|
||||
* @return service name
|
||||
*/
|
||||
String getServiceName();
|
||||
|
||||
/**
|
||||
* Get group name.
|
||||
*
|
||||
* @return group name
|
||||
*/
|
||||
String getGroupName();
|
||||
|
||||
/**
|
||||
* Get clusters.
|
||||
*
|
||||
* @return clusters
|
||||
*/
|
||||
String getClusters();
|
||||
|
||||
/**
|
||||
* Get current instances.
|
||||
*
|
||||
* @return current instances
|
||||
*/
|
||||
List<Instance> getInstances();
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.api.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.selector.client.SelectResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Naming select result.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface NamingResult extends SelectResult<List<Instance>> {
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.api.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.selector.client.Selector;
|
||||
|
||||
/**
|
||||
* Naming selector.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface NamingSelector extends Selector<NamingContext, NamingResult> {
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.api.selector.client;
|
||||
|
||||
/**
|
||||
* Select result.
|
||||
*
|
||||
* @param <T> the type of result
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface SelectResult<T> {
|
||||
|
||||
/**
|
||||
* Get select result.
|
||||
*
|
||||
* @return select result
|
||||
*/
|
||||
T getResult();
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.api.selector.client;
|
||||
|
||||
/**
|
||||
* Client selector.
|
||||
*
|
||||
* @param <C> the type of selector context
|
||||
* @param <E> the type of select result
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface Selector<C, E> {
|
||||
|
||||
/**
|
||||
* select the target result.
|
||||
*
|
||||
* @param context selector context
|
||||
* @return select result
|
||||
*/
|
||||
E select(C context);
|
||||
}
|
@ -24,6 +24,7 @@ import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ListView;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.api.selector.AbstractSelector;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
@ -31,12 +32,15 @@ import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder;
|
||||
import com.alibaba.nacos.client.naming.core.Balancer;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import com.alibaba.nacos.client.naming.remote.NamingClientProxy;
|
||||
import com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorWrapper;
|
||||
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.client.naming.utils.InitUtils;
|
||||
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
|
||||
import com.alibaba.nacos.client.utils.PreInitUtils;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorFactory;
|
||||
import com.alibaba.nacos.client.utils.ValidatorUtils;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
@ -49,6 +53,7 @@ import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
|
||||
import static com.alibaba.nacos.client.naming.selector.NamingSelectorFactory.getUniqueClusterString;
|
||||
|
||||
/**
|
||||
* Nacos Naming Service.
|
||||
@ -415,12 +420,30 @@ public class NacosNamingService implements NamingService {
|
||||
@Override
|
||||
public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
|
||||
throws NacosException {
|
||||
if (null == listener) {
|
||||
NamingSelector clusterSelector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
doSubscribe(serviceName, groupName, getUniqueClusterString(clusters), clusterSelector, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException {
|
||||
subscribe(serviceName, Constants.DEFAULT_GROUP, selector, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener)
|
||||
throws NacosException {
|
||||
doSubscribe(serviceName, groupName, Constants.NULL, selector, listener);
|
||||
}
|
||||
|
||||
private void doSubscribe(String serviceName, String groupName, String clusters, NamingSelector selector,
|
||||
EventListener listener) throws NacosException {
|
||||
if (selector == null || listener == null) {
|
||||
return;
|
||||
}
|
||||
String clusterString = StringUtils.join(clusters, ",");
|
||||
changeNotifier.registerListener(groupName, serviceName, clusterString, listener);
|
||||
clientProxy.subscribe(serviceName, groupName, clusterString);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, groupName, clusters, selector, listener);
|
||||
notifyIfSubscribed(serviceName, groupName, wrapper);
|
||||
changeNotifier.registerListener(groupName, serviceName, wrapper);
|
||||
clientProxy.subscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -441,10 +464,30 @@ public class NacosNamingService implements NamingService {
|
||||
@Override
|
||||
public void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
|
||||
throws NacosException {
|
||||
String clustersString = StringUtils.join(clusters, ",");
|
||||
changeNotifier.deregisterListener(groupName, serviceName, clustersString, listener);
|
||||
if (!changeNotifier.isSubscribed(groupName, serviceName, clustersString)) {
|
||||
clientProxy.unsubscribe(serviceName, groupName, clustersString);
|
||||
NamingSelector clusterSelector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
unsubscribe(serviceName, groupName, clusterSelector, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException {
|
||||
unsubscribe(serviceName, Constants.DEFAULT_GROUP, selector, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener)
|
||||
throws NacosException {
|
||||
doUnsubscribe(serviceName, groupName, selector, listener);
|
||||
}
|
||||
|
||||
private void doUnsubscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener)
|
||||
throws NacosException {
|
||||
if (selector == null || listener == null) {
|
||||
return;
|
||||
}
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(selector, listener);
|
||||
changeNotifier.deregisterListener(groupName, serviceName, wrapper);
|
||||
if (!changeNotifier.isSubscribed(groupName, serviceName)) {
|
||||
clientProxy.unsubscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +528,6 @@ public class NacosNamingService implements NamingService {
|
||||
serviceInfoHolder.shutdown();
|
||||
clientProxy.shutdown();
|
||||
NotifyCenter.deregisterSubscriber(changeNotifier);
|
||||
|
||||
}
|
||||
|
||||
private void batchCheckAndStripGroupNamePrefix(List<Instance> instances, String groupName) throws NacosException {
|
||||
@ -500,9 +542,28 @@ public class NacosNamingService implements NamingService {
|
||||
String groupNameOfInstance = NamingUtils.getGroupName(serviceName);
|
||||
if (!groupName.equals(groupNameOfInstance)) {
|
||||
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, String.format(
|
||||
"wrong group name prefix of instance service name! it should be: %s, Instance: %s", groupName, instance));
|
||||
"wrong group name prefix of instance service name! it should be: %s, Instance: %s", groupName,
|
||||
instance));
|
||||
}
|
||||
instance.setServiceName(NamingUtils.getServiceName(serviceName));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyIfSubscribed(String serviceName, String groupName, NamingSelectorWrapper wrapper) {
|
||||
if (changeNotifier.isSubscribed(groupName, serviceName)) {
|
||||
ServiceInfo serviceInfo = serviceInfoHolder.getServiceInfo(serviceName, groupName, Constants.NULL);
|
||||
InstancesChangeEvent event = transferToEvent(serviceInfo);
|
||||
wrapper.notifyListener(event);
|
||||
}
|
||||
}
|
||||
|
||||
private InstancesChangeEvent transferToEvent(ServiceInfo serviceInfo) {
|
||||
if (serviceInfo == null) {
|
||||
return null;
|
||||
}
|
||||
InstancesDiff diff = new InstancesDiff();
|
||||
diff.setAddedInstances(serviceInfo.getHosts());
|
||||
return new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
|
||||
serviceInfo.getClusters(), serviceInfo.getHosts(), diff);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.alibaba.nacos.client.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.client.naming.backups.FailoverReactor;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
|
||||
import com.alibaba.nacos.client.naming.utils.CacheDirUtil;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import com.alibaba.nacos.common.lifecycle.Closeable;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
@ -130,23 +131,24 @@ public class ServiceInfoHolder implements Closeable {
|
||||
ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
|
||||
if (isEmptyOrErrorPush(serviceInfo)) {
|
||||
//empty or error push, just ignore
|
||||
NAMING_LOGGER.warn("process service info but found empty or error push, serviceKey: {}, "
|
||||
NAMING_LOGGER.warn("process service info but found empty or error push, serviceKey: {}, "
|
||||
+ "pushEmptyProtection: {}, hosts: {}", serviceKey, pushEmptyProtection, serviceInfo.getHosts());
|
||||
return oldService;
|
||||
}
|
||||
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
|
||||
boolean changed = isChangedServiceInfo(oldService, serviceInfo);
|
||||
InstancesDiff diff = getServiceInfoDiff(oldService, serviceInfo);
|
||||
if (StringUtils.isBlank(serviceInfo.getJsonFromServer())) {
|
||||
serviceInfo.setJsonFromServer(JacksonUtils.toJson(serviceInfo));
|
||||
}
|
||||
MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());
|
||||
if (changed) {
|
||||
if (diff.hasDifferent()) {
|
||||
NAMING_LOGGER.info("current ips:({}) service: {} -> {}", serviceInfo.ipCount(), serviceInfo.getKey(),
|
||||
JacksonUtils.toJson(serviceInfo.getHosts()));
|
||||
|
||||
if (!failoverReactor.isFailoverSwitch(serviceKey)) {
|
||||
NotifyCenter.publishEvent(
|
||||
new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
|
||||
serviceInfo.getClusters(), serviceInfo.getHosts()));
|
||||
serviceInfo.getClusters(), serviceInfo.getHosts(), diff));
|
||||
}
|
||||
DiskCache.write(serviceInfo, cacheDir);
|
||||
}
|
||||
@ -162,20 +164,26 @@ public class ServiceInfoHolder implements Closeable {
|
||||
*
|
||||
* @param oldService old service data
|
||||
* @param newService new service data
|
||||
* @return
|
||||
* @return {@code true} if oldService is not equal newService, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isChangedServiceInfo(ServiceInfo oldService, ServiceInfo newService) {
|
||||
return getServiceInfoDiff(oldService, newService).hasDifferent();
|
||||
}
|
||||
|
||||
private InstancesDiff getServiceInfoDiff(ServiceInfo oldService, ServiceInfo newService) {
|
||||
InstancesDiff instancesDiff = new InstancesDiff();
|
||||
if (null == oldService) {
|
||||
NAMING_LOGGER.info("init new ips({}) service: {} -> {}", newService.ipCount(), newService.getKey(),
|
||||
JacksonUtils.toJson(newService.getHosts()));
|
||||
return true;
|
||||
instancesDiff.setAddedInstances(newService.getHosts());
|
||||
return instancesDiff;
|
||||
}
|
||||
if (oldService.getLastRefTime() > newService.getLastRefTime()) {
|
||||
NAMING_LOGGER.warn("out of date data received, old-t: {}, new-t: {}", oldService.getLastRefTime(),
|
||||
newService.getLastRefTime());
|
||||
return false;
|
||||
return instancesDiff;
|
||||
}
|
||||
boolean changed = false;
|
||||
|
||||
Map<String, Instance> oldHostMap = new HashMap<>(oldService.getHosts().size());
|
||||
for (Instance host : oldService.getHosts()) {
|
||||
oldHostMap.put(host.toInetAddr(), host);
|
||||
@ -215,23 +223,23 @@ public class ServiceInfoHolder implements Closeable {
|
||||
}
|
||||
|
||||
if (newHosts.size() > 0) {
|
||||
changed = true;
|
||||
NAMING_LOGGER.info("new ips({}) service: {} -> {}", newHosts.size(), newService.getKey(),
|
||||
JacksonUtils.toJson(newHosts));
|
||||
instancesDiff.setAddedInstances(newHosts);
|
||||
}
|
||||
|
||||
if (remvHosts.size() > 0) {
|
||||
changed = true;
|
||||
NAMING_LOGGER.info("removed ips({}) service: {} -> {}", remvHosts.size(), newService.getKey(),
|
||||
JacksonUtils.toJson(remvHosts));
|
||||
instancesDiff.setRemovedInstances(remvHosts);
|
||||
}
|
||||
|
||||
if (modHosts.size() > 0) {
|
||||
changed = true;
|
||||
NAMING_LOGGER.info("modified ips({}) service: {} -> {}", modHosts.size(), newService.getKey(),
|
||||
JacksonUtils.toJson(modHosts));
|
||||
instancesDiff.setModifiedInstances(modHosts);
|
||||
}
|
||||
return changed;
|
||||
return instancesDiff;
|
||||
}
|
||||
|
||||
public String getCacheDir() {
|
||||
|
@ -183,7 +183,7 @@ public class ServiceInfoUpdateService implements Closeable {
|
||||
long delayTime = DEFAULT_DELAY;
|
||||
|
||||
try {
|
||||
if (!changeNotifier.isSubscribed(groupName, serviceName, clusters) && !futureMap.containsKey(
|
||||
if (!changeNotifier.isSubscribed(groupName, serviceName) && !futureMap.containsKey(
|
||||
serviceKey)) {
|
||||
NAMING_LOGGER.info("update task is stopped, service:{}, clusters:{}", groupedServiceName, clusters);
|
||||
isCancel = true;
|
||||
|
@ -40,13 +40,20 @@ public class InstancesChangeEvent extends Event {
|
||||
private final String clusters;
|
||||
|
||||
private final List<Instance> hosts;
|
||||
|
||||
private InstancesDiff instancesDiff;
|
||||
|
||||
public InstancesChangeEvent(String eventScope, String serviceName, String groupName, String clusters, List<Instance> hosts) {
|
||||
this(eventScope, serviceName, groupName, clusters, hosts, null);
|
||||
}
|
||||
|
||||
public InstancesChangeEvent(String eventScope, String serviceName, String groupName, String clusters, List<Instance> hosts, InstancesDiff diff) {
|
||||
this.eventScope = eventScope;
|
||||
this.serviceName = serviceName;
|
||||
this.groupName = groupName;
|
||||
this.clusters = clusters;
|
||||
this.hosts = hosts;
|
||||
this.instancesDiff = diff;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
@ -64,7 +71,11 @@ public class InstancesChangeEvent extends Event {
|
||||
public List<Instance> getHosts() {
|
||||
return hosts;
|
||||
}
|
||||
|
||||
|
||||
public InstancesDiff getInstancesDiff() {
|
||||
return instancesDiff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scope() {
|
||||
return this.eventScope;
|
||||
|
@ -16,22 +16,18 @@
|
||||
|
||||
package com.alibaba.nacos.client.naming.event;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorWrapper;
|
||||
import com.alibaba.nacos.client.selector.SelectorManager;
|
||||
import com.alibaba.nacos.common.JustForTest;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* A subscriber to notify eventListener callback.
|
||||
@ -43,7 +39,7 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
|
||||
|
||||
private final String eventScope;
|
||||
|
||||
private final Map<String, ConcurrentHashSet<EventListener>> listenerMap = new ConcurrentHashMap<>();
|
||||
private final SelectorManager<NamingSelectorWrapper> selectorManager = new SelectorManager<>();
|
||||
|
||||
@JustForTest
|
||||
public InstancesChangeNotifier() {
|
||||
@ -59,13 +55,14 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
|
||||
*
|
||||
* @param groupName group name
|
||||
* @param serviceName serviceName
|
||||
* @param clusters clusters, concat by ','. such as 'xxx,yyy'
|
||||
* @param listener custom listener
|
||||
* @param wrapper selectorWrapper
|
||||
*/
|
||||
public void registerListener(String groupName, String serviceName, String clusters, EventListener listener) {
|
||||
String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
|
||||
ConcurrentHashSet<EventListener> eventListeners = listenerMap.computeIfAbsent(key, keyInner -> new ConcurrentHashSet<>());
|
||||
eventListeners.add(listener);
|
||||
public void registerListener(String groupName, String serviceName, NamingSelectorWrapper wrapper) {
|
||||
if (wrapper == null) {
|
||||
return;
|
||||
}
|
||||
String subId = NamingUtils.getGroupedName(serviceName, groupName);
|
||||
selectorManager.addSelectorWrapper(subId, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,38 +70,31 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
|
||||
*
|
||||
* @param groupName group name
|
||||
* @param serviceName serviceName
|
||||
* @param clusters clusters, concat by ','. such as 'xxx,yyy'
|
||||
* @param listener custom listener
|
||||
* @param wrapper selectorWrapper
|
||||
*/
|
||||
public void deregisterListener(String groupName, String serviceName, String clusters, EventListener listener) {
|
||||
String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
|
||||
ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);
|
||||
if (eventListeners == null) {
|
||||
public void deregisterListener(String groupName, String serviceName, NamingSelectorWrapper wrapper) {
|
||||
if (wrapper == null) {
|
||||
return;
|
||||
}
|
||||
eventListeners.remove(listener);
|
||||
if (CollectionUtils.isEmpty(eventListeners)) {
|
||||
listenerMap.remove(key);
|
||||
}
|
||||
String subId = NamingUtils.getGroupedName(serviceName, groupName);
|
||||
selectorManager.removeSelectorWrapper(subId, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* check serviceName,clusters is subscribed.
|
||||
* check serviceName,groupName is subscribed.
|
||||
*
|
||||
* @param groupName group name
|
||||
* @param serviceName serviceName
|
||||
* @param clusters clusters, concat by ','. such as 'xxx,yyy'
|
||||
* @return is serviceName,clusters subscribed
|
||||
*/
|
||||
public boolean isSubscribed(String groupName, String serviceName, String clusters) {
|
||||
String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
|
||||
ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);
|
||||
return CollectionUtils.isNotEmpty(eventListeners);
|
||||
public boolean isSubscribed(String groupName, String serviceName) {
|
||||
String subId = NamingUtils.getGroupedName(serviceName, groupName);
|
||||
return selectorManager.isSubscribed(subId);
|
||||
}
|
||||
|
||||
public List<ServiceInfo> getSubscribeServices() {
|
||||
List<ServiceInfo> serviceInfos = new ArrayList<>();
|
||||
for (String key : listenerMap.keySet()) {
|
||||
for (String key : selectorManager.getSubscriptions()) {
|
||||
serviceInfos.add(ServiceInfo.fromKey(key));
|
||||
}
|
||||
return serviceInfos;
|
||||
@ -112,26 +102,11 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
|
||||
|
||||
@Override
|
||||
public void onEvent(InstancesChangeEvent event) {
|
||||
String key = ServiceInfo
|
||||
.getKey(NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName()), event.getClusters());
|
||||
ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);
|
||||
if (CollectionUtils.isEmpty(eventListeners)) {
|
||||
return;
|
||||
String subId = NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName());
|
||||
Collection<NamingSelectorWrapper> selectorWrappers = selectorManager.getSelectorWrappers(subId);
|
||||
for (NamingSelectorWrapper selectorWrapper : selectorWrappers) {
|
||||
selectorWrapper.notifyListener(event);
|
||||
}
|
||||
for (final EventListener listener : eventListeners) {
|
||||
final com.alibaba.nacos.api.naming.listener.Event namingEvent = transferToNamingEvent(event);
|
||||
if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {
|
||||
((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(namingEvent));
|
||||
} else {
|
||||
listener.onEvent(namingEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private com.alibaba.nacos.api.naming.listener.Event transferToNamingEvent(
|
||||
InstancesChangeEvent instancesChangeEvent) {
|
||||
return new NamingEvent(instancesChangeEvent.getServiceName(), instancesChangeEvent.getGroupName(),
|
||||
instancesChangeEvent.getClusters(), instancesChangeEvent.getHosts());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.event;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The differences in instances compared to the last callback.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public class InstancesDiff {
|
||||
|
||||
private final List<Instance> addedInstances = new ArrayList<>();
|
||||
|
||||
private final List<Instance> removedInstances = new ArrayList<>();
|
||||
|
||||
private final List<Instance> modifiedInstances = new ArrayList<>();
|
||||
|
||||
public InstancesDiff() {
|
||||
}
|
||||
|
||||
public InstancesDiff(List<Instance> addedInstances, List<Instance> removedInstances,
|
||||
List<Instance> modifiedInstances) {
|
||||
setAddedInstances(addedInstances);
|
||||
setRemovedInstances(removedInstances);
|
||||
setModifiedInstances(modifiedInstances);
|
||||
}
|
||||
|
||||
public List<Instance> getAddedInstances() {
|
||||
return addedInstances;
|
||||
}
|
||||
|
||||
public void setAddedInstances(Collection<Instance> addedInstances) {
|
||||
this.addedInstances.clear();
|
||||
if (CollectionUtils.isNotEmpty(addedInstances)) {
|
||||
this.addedInstances.addAll(addedInstances);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Instance> getRemovedInstances() {
|
||||
return removedInstances;
|
||||
}
|
||||
|
||||
public void setRemovedInstances(Collection<Instance> removedInstances) {
|
||||
this.removedInstances.clear();
|
||||
if (CollectionUtils.isNotEmpty(removedInstances)) {
|
||||
this.removedInstances.addAll(removedInstances);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Instance> getModifiedInstances() {
|
||||
return modifiedInstances;
|
||||
}
|
||||
|
||||
public void setModifiedInstances(Collection<Instance> modifiedInstances) {
|
||||
this.modifiedInstances.clear();
|
||||
if (CollectionUtils.isNotEmpty(modifiedInstances)) {
|
||||
this.modifiedInstances.addAll(modifiedInstances);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any instances have changed.
|
||||
*
|
||||
* @return true if there are instances that have changed
|
||||
*/
|
||||
public boolean hasDifferent() {
|
||||
return isAdded() || isRemoved() || isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any instances have been added.
|
||||
*
|
||||
* @return true if there are instances that have been added.
|
||||
*/
|
||||
public boolean isAdded() {
|
||||
return CollectionUtils.isNotEmpty(this.addedInstances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any instances have been added.
|
||||
*
|
||||
* @return true if there are instances that have been added.
|
||||
*/
|
||||
public boolean isRemoved() {
|
||||
return CollectionUtils.isNotEmpty(this.removedInstances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any instances have been added.
|
||||
*
|
||||
* @return true if there are instances that have been added.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return CollectionUtils.isNotEmpty(this.modifiedInstances);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.listener;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.Event;
|
||||
|
||||
/**
|
||||
* Listener for NamingChangeEvent.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public abstract class AbstractNamingChangeListener extends AbstractEventListener {
|
||||
|
||||
@Override
|
||||
public final void onEvent(Event event) {
|
||||
if (event instanceof NamingChangeEvent) {
|
||||
onChange((NamingChangeEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when instances have changed.
|
||||
*
|
||||
* @param event NamingChangeEvent
|
||||
*/
|
||||
public abstract void onChange(NamingChangeEvent event);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.listener;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Naming Event with instance change information.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public class NamingChangeEvent extends NamingEvent {
|
||||
|
||||
private final InstancesDiff instancesDiff;
|
||||
|
||||
public NamingChangeEvent(String serviceName, List<Instance> instances, InstancesDiff instancesDiff) {
|
||||
super(serviceName, instances);
|
||||
this.instancesDiff = instancesDiff;
|
||||
}
|
||||
|
||||
public NamingChangeEvent(String serviceName, String groupName, String clusters, List<Instance> instances,
|
||||
InstancesDiff instancesDiff) {
|
||||
super(serviceName, groupName, clusters, instances);
|
||||
this.instancesDiff = instancesDiff;
|
||||
}
|
||||
|
||||
public boolean isAdded() {
|
||||
return this.instancesDiff.isAdded();
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return this.instancesDiff.isRemoved();
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return this.instancesDiff.isModified();
|
||||
}
|
||||
|
||||
public List<Instance> getAddedInstances() {
|
||||
return this.instancesDiff.getAddedInstances();
|
||||
}
|
||||
|
||||
public List<Instance> getRemovedInstances() {
|
||||
return this.instancesDiff.getRemovedInstances();
|
||||
}
|
||||
|
||||
public List<Instance> getModifiedInstances() {
|
||||
return this.instancesDiff.getModifiedInstances();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingContext;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingResult;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Default naming selector.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public class DefaultNamingSelector implements NamingSelector {
|
||||
|
||||
private final Predicate<Instance> filter;
|
||||
|
||||
public DefaultNamingSelector(Predicate<Instance> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamingResult select(NamingContext context) {
|
||||
List<Instance> instances = doFilter(context.getInstances());
|
||||
return () -> instances;
|
||||
}
|
||||
|
||||
private List<Instance> doFilter(List<Instance> instances) {
|
||||
return instances == null ? Collections.emptyList()
|
||||
: instances.stream().filter(filter).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.client.selector.ListenerInvoker;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Naming listener invoker.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public class NamingListenerInvoker implements ListenerInvoker<NamingEvent> {
|
||||
|
||||
private final EventListener listener;
|
||||
|
||||
public NamingListenerInvoker(EventListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(NamingEvent event) {
|
||||
if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {
|
||||
((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(event));
|
||||
} else {
|
||||
listener.onEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NamingListenerInvoker that = (NamingListenerInvoker) o;
|
||||
return Objects.equals(listener, that.listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(listener);
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Selectors factory.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public final class NamingSelectorFactory {
|
||||
|
||||
public static final NamingSelector EMPTY_SELECTOR = context -> context::getInstances;
|
||||
|
||||
public static final NamingSelector HEALTHY_SELECTOR = new DefaultNamingSelector(Instance::isHealthy);
|
||||
|
||||
/**
|
||||
* Cluster selector.
|
||||
*/
|
||||
private static class ClusterSelector extends DefaultNamingSelector {
|
||||
|
||||
private final String clusterString;
|
||||
|
||||
public ClusterSelector(Predicate<Instance> filter, String clusterString) {
|
||||
super(filter);
|
||||
this.clusterString = clusterString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ClusterSelector that = (ClusterSelector) o;
|
||||
return Objects.equals(this.clusterString, that.clusterString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.clusterString);
|
||||
}
|
||||
}
|
||||
|
||||
private NamingSelectorFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cluster selector.
|
||||
*
|
||||
* @param clusters target cluster
|
||||
* @return cluster selector
|
||||
*/
|
||||
public static NamingSelector newClusterSelector(Collection<String> clusters) {
|
||||
if (CollectionUtils.isNotEmpty(clusters)) {
|
||||
final Set<String> set = new HashSet<>(clusters);
|
||||
Predicate<Instance> filter = instance -> set.contains(instance.getClusterName());
|
||||
String clusterString = getUniqueClusterString(clusters);
|
||||
return new ClusterSelector(filter, clusterString);
|
||||
} else {
|
||||
return EMPTY_SELECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a IP selector.
|
||||
*
|
||||
* @param regex regular expression of IP
|
||||
* @return IP selector
|
||||
*/
|
||||
public static NamingSelector newIpSelector(String regex) {
|
||||
if (regex == null) {
|
||||
throw new IllegalArgumentException("The parameter 'regex' cannot be null.");
|
||||
}
|
||||
return new DefaultNamingSelector(instance -> Pattern.matches(regex, instance.getIp()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a metadata selector.
|
||||
*
|
||||
* @param metadata metadata that needs to be matched
|
||||
* @return metadata selector
|
||||
*/
|
||||
public static NamingSelector newMetadataSelector(Map<String, String> metadata) {
|
||||
return newMetadataSelector(metadata, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a metadata selector.
|
||||
*
|
||||
* @param metadata target metadata
|
||||
* @param isAny true if any of the metadata needs to be matched, false if all the metadata need to be matched.
|
||||
* @return metadata selector
|
||||
*/
|
||||
public static NamingSelector newMetadataSelector(Map<String, String> metadata, boolean isAny) {
|
||||
if (metadata == null) {
|
||||
throw new IllegalArgumentException("The parameter 'metadata' cannot be null.");
|
||||
}
|
||||
|
||||
Predicate<Instance> filter = instance -> instance.getMetadata().size() >= metadata.size();
|
||||
|
||||
for (Map.Entry<String, String> entry : metadata.entrySet()) {
|
||||
Predicate<Instance> nextFilter = instance -> {
|
||||
Map<String, String> map = instance.getMetadata();
|
||||
return Objects.equals(map.get(entry.getKey()), entry.getValue());
|
||||
};
|
||||
if (isAny) {
|
||||
filter = filter.or(nextFilter);
|
||||
} else {
|
||||
filter = filter.and(nextFilter);
|
||||
}
|
||||
}
|
||||
return new DefaultNamingSelector(filter);
|
||||
}
|
||||
|
||||
public static String getUniqueClusterString(Collection<String> cluster) {
|
||||
TreeSet<String> treeSet = new TreeSet<>(cluster);
|
||||
return StringUtils.join(treeSet, ",");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingContext;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import com.alibaba.nacos.client.naming.listener.NamingChangeEvent;
|
||||
import com.alibaba.nacos.client.selector.AbstractSelectorWrapper;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Naming selector wrapper.
|
||||
*
|
||||
* @author lideyou
|
||||
*/
|
||||
public class NamingSelectorWrapper extends AbstractSelectorWrapper<NamingSelector, NamingEvent, InstancesChangeEvent> {
|
||||
|
||||
private String serviceName;
|
||||
|
||||
private String groupName;
|
||||
|
||||
private String clusters;
|
||||
|
||||
private final InnerNamingContext namingContext = new InnerNamingContext();
|
||||
|
||||
private class InnerNamingContext implements NamingContext {
|
||||
|
||||
private List<Instance> instances;
|
||||
|
||||
@Override
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClusters() {
|
||||
return clusters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Instance> getInstances() {
|
||||
return instances;
|
||||
}
|
||||
|
||||
private void setInstances(List<Instance> instances) {
|
||||
this.instances = instances;
|
||||
}
|
||||
}
|
||||
|
||||
public NamingSelectorWrapper(NamingSelector selector, EventListener listener) {
|
||||
super(selector, new NamingListenerInvoker(listener));
|
||||
}
|
||||
|
||||
public NamingSelectorWrapper(String serviceName, String groupName, String clusters, NamingSelector selector,
|
||||
EventListener listener) {
|
||||
this(selector, listener);
|
||||
this.serviceName = serviceName;
|
||||
this.groupName = groupName;
|
||||
this.clusters = clusters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSelectable(InstancesChangeEvent event) {
|
||||
return event != null && event.getHosts() != null && event.getInstancesDiff() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallable(NamingEvent event) {
|
||||
if (event == null) {
|
||||
return false;
|
||||
}
|
||||
NamingChangeEvent changeEvent = (NamingChangeEvent) event;
|
||||
return changeEvent.isAdded() || changeEvent.isRemoved() || changeEvent.isModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamingEvent buildListenerEvent(InstancesChangeEvent event) {
|
||||
List<Instance> currentIns = Collections.emptyList();
|
||||
if (CollectionUtils.isNotEmpty(event.getHosts())) {
|
||||
currentIns = doSelect(event.getHosts());
|
||||
}
|
||||
|
||||
InstancesDiff diff = event.getInstancesDiff();
|
||||
InstancesDiff newDiff = new InstancesDiff();
|
||||
if (diff.isAdded()) {
|
||||
newDiff.setAddedInstances(doSelect(diff.getAddedInstances()));
|
||||
}
|
||||
if (diff.isRemoved()) {
|
||||
newDiff.setRemovedInstances(doSelect(diff.getRemovedInstances()));
|
||||
}
|
||||
if (diff.isModified()) {
|
||||
newDiff.setModifiedInstances(doSelect(diff.getModifiedInstances()));
|
||||
}
|
||||
|
||||
return new NamingChangeEvent(serviceName, groupName, clusters, currentIns, newDiff);
|
||||
}
|
||||
|
||||
private List<Instance> doSelect(List<Instance> instances) {
|
||||
NamingContext context = getNamingContext(instances);
|
||||
return this.getSelector().select(context).getResult();
|
||||
}
|
||||
|
||||
private NamingContext getNamingContext(final List<Instance> instances) {
|
||||
namingContext.setInstances(instances);
|
||||
return namingContext;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.selector;
|
||||
|
||||
import com.alibaba.nacos.api.selector.client.Selector;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Selector Wrapper.
|
||||
*
|
||||
* @param <S> the type of selector
|
||||
* @param <T> the type of original event
|
||||
* @param <E> the type of listener callback event
|
||||
* @author lideyou
|
||||
*/
|
||||
public abstract class AbstractSelectorWrapper<S extends Selector<?, ?>, E, T extends Event> {
|
||||
|
||||
private final S selector;
|
||||
|
||||
private final ListenerInvoker<E> listener;
|
||||
|
||||
public AbstractSelectorWrapper(S selector, ListenerInvoker<E> listener) {
|
||||
this.selector = selector;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the event can be callback.
|
||||
*
|
||||
* @param event original event
|
||||
* @return true if the event can be callback
|
||||
*/
|
||||
protected abstract boolean isSelectable(T event);
|
||||
|
||||
/**
|
||||
* Check whether the result can be callback.
|
||||
*
|
||||
* @param event select result
|
||||
* @return true if the result can be callback
|
||||
*/
|
||||
protected abstract boolean isCallable(E event);
|
||||
|
||||
/**
|
||||
* Build an event received by the listener.
|
||||
*
|
||||
* @param event original event
|
||||
* @return listener event
|
||||
*/
|
||||
protected abstract E buildListenerEvent(T event);
|
||||
|
||||
/**
|
||||
* Notify listener.
|
||||
*
|
||||
* @param event original event
|
||||
*/
|
||||
public void notifyListener(T event) {
|
||||
if (!isSelectable(event)) {
|
||||
return;
|
||||
}
|
||||
E newEvent = buildListenerEvent(event);
|
||||
if (isCallable(newEvent)) {
|
||||
listener.invoke(newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public ListenerInvoker<E> getListener() {
|
||||
return this.listener;
|
||||
}
|
||||
|
||||
public S getSelector() {
|
||||
return this.selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AbstractSelectorWrapper<?, ?, ?> that = (AbstractSelectorWrapper<?, ?, ?>) o;
|
||||
return Objects.equals(selector, that.selector) && Objects.equals(listener, that.listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(selector, listener);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.selector;
|
||||
|
||||
/**
|
||||
* Listener invoker.
|
||||
*
|
||||
* @param <E> the type of event received by the listener
|
||||
* @author lideyou
|
||||
*/
|
||||
public interface ListenerInvoker<E> {
|
||||
|
||||
/**
|
||||
* Invoke inner listener.
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
void invoke(E event);
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.selector;
|
||||
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Selector Manager.
|
||||
*
|
||||
* @param <S> the type of selector wrapper
|
||||
* @author lideyou
|
||||
*/
|
||||
public class SelectorManager<S extends AbstractSelectorWrapper<?, ?, ?>> {
|
||||
|
||||
Map<String, Set<S>> selectorMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Add a selectorWrapper to subId.
|
||||
*
|
||||
* @param subId subscription id
|
||||
* @param wrapper selector wrapper
|
||||
*/
|
||||
public void addSelectorWrapper(String subId, S wrapper) {
|
||||
selectorMap.compute(subId, (k, v) -> {
|
||||
if (v == null) {
|
||||
v = new ConcurrentHashSet<>();
|
||||
}
|
||||
v.add(wrapper);
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all SelectorWrappers by id.
|
||||
*
|
||||
* @param subId subscription id
|
||||
* @return the set of SelectorWrappers
|
||||
*/
|
||||
public Set<S> getSelectorWrappers(String subId) {
|
||||
return selectorMap.getOrDefault(subId, Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a SelectorWrapper by id.
|
||||
*
|
||||
* @param subId subscription id
|
||||
* @param wrapper selector wrapper
|
||||
*/
|
||||
public void removeSelectorWrapper(String subId, S wrapper) {
|
||||
selectorMap.computeIfPresent(subId, (k, v) -> {
|
||||
v.remove(wrapper);
|
||||
return v.isEmpty() ? null : v;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a subscription by id.
|
||||
*
|
||||
* @param subId subscription id
|
||||
*/
|
||||
public void removeSubscription(String subId) {
|
||||
selectorMap.remove(subId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all subscriptions.
|
||||
*
|
||||
* @return all subscriptions
|
||||
*/
|
||||
public Set<String> getSubscriptions() {
|
||||
return selectorMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether subId is subscribed.
|
||||
*
|
||||
* @param subId subscription id
|
||||
* @return true if is subscribed
|
||||
*/
|
||||
public boolean isSubscribed(String subId) {
|
||||
return CollectionUtils.isNotEmpty(this.getSelectorWrappers(subId));
|
||||
}
|
||||
}
|
@ -30,6 +30,8 @@ import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier;
|
||||
import com.alibaba.nacos.client.naming.remote.NamingClientProxy;
|
||||
import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorFactory;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorWrapper;
|
||||
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@ -46,6 +48,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.nacos.client.naming.selector.NamingSelectorFactory.getUniqueClusterString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@ -800,8 +803,10 @@ class NacosNamingServiceTest {
|
||||
};
|
||||
//when
|
||||
client.subscribe(serviceName, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, Constants.DEFAULT_GROUP, Constants.NULL,
|
||||
NamingSelectorFactory.newClusterSelector(Collections.emptyList()), listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).registerListener(Constants.DEFAULT_GROUP, serviceName, "", listener);
|
||||
verify(changeNotifier, times(1)).registerListener(Constants.DEFAULT_GROUP, serviceName, wrapper);
|
||||
verify(proxy, times(1)).subscribe(serviceName, Constants.DEFAULT_GROUP, "");
|
||||
}
|
||||
|
||||
@ -815,8 +820,10 @@ class NacosNamingServiceTest {
|
||||
};
|
||||
//when
|
||||
client.subscribe(serviceName, groupName, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, groupName, Constants.NULL,
|
||||
NamingSelectorFactory.newClusterSelector(Collections.emptyList()), listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).registerListener(groupName, serviceName, "", listener);
|
||||
verify(changeNotifier, times(1)).registerListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).subscribe(serviceName, groupName, "");
|
||||
}
|
||||
|
||||
@ -830,10 +837,11 @@ class NacosNamingServiceTest {
|
||||
};
|
||||
//when
|
||||
client.subscribe(serviceName, clusterList, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, Constants.DEFAULT_GROUP, Constants.NULL,
|
||||
NamingSelectorFactory.newClusterSelector(clusterList), listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).registerListener(Constants.DEFAULT_GROUP, serviceName, "cluster1,cluster2",
|
||||
listener);
|
||||
verify(proxy, times(1)).subscribe(serviceName, Constants.DEFAULT_GROUP, "cluster1,cluster2");
|
||||
verify(changeNotifier, times(1)).registerListener(Constants.DEFAULT_GROUP, serviceName, wrapper);
|
||||
verify(proxy, times(1)).subscribe(serviceName, Constants.DEFAULT_GROUP, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -847,9 +855,27 @@ class NacosNamingServiceTest {
|
||||
};
|
||||
//when
|
||||
client.subscribe(serviceName, groupName, clusterList, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, groupName,
|
||||
getUniqueClusterString(clusterList), NamingSelectorFactory.newClusterSelector(clusterList), listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).registerListener(groupName, serviceName, "cluster1,cluster2", listener);
|
||||
verify(proxy, times(1)).subscribe(serviceName, groupName, "cluster1,cluster2");
|
||||
verify(changeNotifier, times(1)).registerListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).subscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe5() throws NacosException {
|
||||
String serviceName = "service1";
|
||||
String groupName = "group1";
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
//when
|
||||
client.subscribe(serviceName, groupName, NamingSelectorFactory.HEALTHY_SELECTOR, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(serviceName, groupName, Constants.NULL,
|
||||
NamingSelectorFactory.HEALTHY_SELECTOR, listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).registerListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).subscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -859,7 +885,8 @@ class NacosNamingServiceTest {
|
||||
//when
|
||||
client.subscribe(serviceName, groupName, null);
|
||||
//then
|
||||
verify(changeNotifier, never()).registerListener(groupName, serviceName, "", null);
|
||||
verify(changeNotifier, never()).registerListener(groupName, serviceName,
|
||||
new NamingSelectorWrapper(NamingSelectorFactory.newIpSelector(""), null));
|
||||
verify(proxy, never()).subscribe(serviceName, groupName, "");
|
||||
|
||||
}
|
||||
@ -871,10 +898,14 @@ class NacosNamingServiceTest {
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
when(changeNotifier.isSubscribed(Constants.DEFAULT_GROUP, serviceName)).thenReturn(false);
|
||||
//when
|
||||
client.unsubscribe(serviceName, listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(Constants.DEFAULT_GROUP, serviceName, "", listener);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, Constants.DEFAULT_GROUP, "");
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(
|
||||
NamingSelectorFactory.newClusterSelector(Collections.emptyList()), listener);
|
||||
verify(changeNotifier, times(1)).deregisterListener(Constants.DEFAULT_GROUP, serviceName, wrapper);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, Constants.DEFAULT_GROUP, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -885,10 +916,15 @@ class NacosNamingServiceTest {
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
when(changeNotifier.isSubscribed(groupName, serviceName)).thenReturn(false);
|
||||
|
||||
//when
|
||||
client.unsubscribe(serviceName, groupName, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(
|
||||
NamingSelectorFactory.newClusterSelector(Collections.emptyList()), listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(groupName, serviceName, "", listener);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, groupName, "");
|
||||
verify(changeNotifier, times(1)).deregisterListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -899,11 +935,15 @@ class NacosNamingServiceTest {
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
when(changeNotifier.isSubscribed(Constants.DEFAULT_GROUP, serviceName)).thenReturn(false);
|
||||
|
||||
//when
|
||||
client.unsubscribe(serviceName, clusterList, listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(Constants.DEFAULT_GROUP, serviceName, "cluster1,cluster2",
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(NamingSelectorFactory.newClusterSelector(clusterList),
|
||||
listener);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, Constants.DEFAULT_GROUP, "cluster1,cluster2");
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(Constants.DEFAULT_GROUP, serviceName, wrapper);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, Constants.DEFAULT_GROUP, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -915,10 +955,33 @@ class NacosNamingServiceTest {
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
when(changeNotifier.isSubscribed(groupName, serviceName)).thenReturn(false);
|
||||
|
||||
//when
|
||||
client.unsubscribe(serviceName, groupName, clusterList, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(NamingSelectorFactory.newClusterSelector(clusterList),
|
||||
listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(groupName, serviceName, "cluster1,cluster2", listener);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, groupName, "cluster1,cluster2");
|
||||
verify(changeNotifier, times(1)).deregisterListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnSubscribe5() throws NacosException {
|
||||
//given
|
||||
String serviceName = "service1";
|
||||
String groupName = "group1";
|
||||
EventListener listener = event -> {
|
||||
|
||||
};
|
||||
when(changeNotifier.isSubscribed(groupName, serviceName)).thenReturn(false);
|
||||
|
||||
//when
|
||||
client.unsubscribe(serviceName, groupName, NamingSelectorFactory.HEALTHY_SELECTOR, listener);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(NamingSelectorFactory.HEALTHY_SELECTOR, listener);
|
||||
//then
|
||||
verify(changeNotifier, times(1)).deregisterListener(groupName, serviceName, wrapper);
|
||||
verify(proxy, times(1)).unsubscribe(serviceName, groupName, Constants.NULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -23,6 +23,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class InstancesChangeEventTest {
|
||||
|
||||
@ -35,7 +36,10 @@ class InstancesChangeEventTest {
|
||||
List<Instance> hosts = new ArrayList<>();
|
||||
Instance ins = new Instance();
|
||||
hosts.add(ins);
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(eventScope, serviceName, groupName, clusters, hosts);
|
||||
InstancesDiff diff = new InstancesDiff();
|
||||
diff.setAddedInstances(hosts);
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(eventScope, serviceName, groupName, clusters, hosts,
|
||||
diff);
|
||||
assertEquals(eventScope, event.scope());
|
||||
assertEquals(serviceName, event.getServiceName());
|
||||
assertEquals(clusters, event.getClusters());
|
||||
@ -43,5 +47,11 @@ class InstancesChangeEventTest {
|
||||
List<Instance> hosts1 = event.getHosts();
|
||||
assertEquals(hosts.size(), hosts1.size());
|
||||
assertEquals(hosts.get(0), hosts1.get(0));
|
||||
InstancesDiff diff1 = event.getInstancesDiff();
|
||||
assertTrue(diff1.hasDifferent());
|
||||
assertEquals(diff.getAddedInstances().size(), diff1.getAddedInstances().size());
|
||||
assertEquals(diff.getAddedInstances().get(0), diff.getAddedInstances().get(0));
|
||||
assertEquals(diff.getRemovedInstances().size(), diff1.getRemovedInstances().size());
|
||||
assertEquals(diff.getModifiedInstances().size(), diff1.getModifiedInstances().size());
|
||||
}
|
||||
}
|
@ -20,15 +20,22 @@ import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.client.naming.selector.DefaultNamingSelector;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorFactory;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorWrapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -38,124 +45,123 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
class InstancesChangeNotifierTest {
|
||||
|
||||
private static final String EVENT_SCOPE_CASE = "scope-001";
|
||||
|
||||
private static final String GROUP_CASE = "a";
|
||||
|
||||
private static final String SERVICE_NAME_CASE = "b";
|
||||
|
||||
private static final String CLUSTER_STR_CASE = "c";
|
||||
|
||||
InstancesChangeNotifier instancesChangeNotifier;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
instancesChangeNotifier = new InstancesChangeNotifier(EVENT_SCOPE_CASE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterListener() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
List<String> clusters = Collections.singletonList(CLUSTER_STR_CASE);
|
||||
EventListener listener = Mockito.mock(EventListener.class);
|
||||
instancesChangeNotifier.registerListener(group, name, clusters, listener);
|
||||
NamingSelector selector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(SERVICE_NAME_CASE, GROUP_CASE, CLUSTER_STR_CASE,
|
||||
selector, listener);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE, wrapper);
|
||||
List<ServiceInfo> subscribeServices = instancesChangeNotifier.getSubscribeServices();
|
||||
assertEquals(1, subscribeServices.size());
|
||||
assertEquals(group, subscribeServices.get(0).getGroupName());
|
||||
assertEquals(name, subscribeServices.get(0).getName());
|
||||
assertEquals(clusters, subscribeServices.get(0).getClusters());
|
||||
assertEquals(GROUP_CASE, subscribeServices.get(0).getGroupName());
|
||||
assertEquals(SERVICE_NAME_CASE, subscribeServices.get(0).getName());
|
||||
assertNull(subscribeServices.get(0).getClusters());
|
||||
|
||||
List<Instance> hosts = new ArrayList<>();
|
||||
Instance ins = new Instance();
|
||||
hosts.add(ins);
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(eventScope, name, group, clusters, hosts);
|
||||
InstancesDiff diff = new InstancesDiff();
|
||||
diff.setAddedInstances(hosts);
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(EVENT_SCOPE_CASE, SERVICE_NAME_CASE, GROUP_CASE,
|
||||
CLUSTER_STR_CASE, hosts, diff);
|
||||
assertTrue(instancesChangeNotifier.scopeMatches(event));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeregisterListener() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
List<String> clusters = Collections.singletonList(CLUSTER_STR_CASE);
|
||||
EventListener listener = Mockito.mock(EventListener.class);
|
||||
instancesChangeNotifier.registerListener(group, name, clusters, listener);
|
||||
NamingSelector selector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(selector, listener);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE, wrapper);
|
||||
List<ServiceInfo> subscribeServices = instancesChangeNotifier.getSubscribeServices();
|
||||
assertEquals(1, subscribeServices.size());
|
||||
|
||||
instancesChangeNotifier.deregisterListener(group, name, clusters, listener);
|
||||
instancesChangeNotifier.deregisterListener(GROUP_CASE, SERVICE_NAME_CASE, wrapper);
|
||||
|
||||
List<ServiceInfo> subscribeServices2 = instancesChangeNotifier.getSubscribeServices();
|
||||
assertEquals(0, subscribeServices2.size());
|
||||
|
||||
instancesChangeNotifier.deregisterListener(group, name, clusters, listener);
|
||||
assertEquals(0, subscribeServices2.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsSubscribed() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
List<String> clusters = Collections.singletonList(CLUSTER_STR_CASE);
|
||||
EventListener listener = Mockito.mock(EventListener.class);
|
||||
assertFalse(instancesChangeNotifier.isSubscribed(group, name, clusters));
|
||||
NamingSelector selector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
assertFalse(instancesChangeNotifier.isSubscribed(GROUP_CASE, SERVICE_NAME_CASE));
|
||||
|
||||
instancesChangeNotifier.registerListener(group, name, clusters, listener);
|
||||
assertTrue(instancesChangeNotifier.isSubscribed(group, name, clusters));
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(SERVICE_NAME_CASE, GROUP_CASE, CLUSTER_STR_CASE,
|
||||
selector, listener);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE, wrapper);
|
||||
assertTrue(instancesChangeNotifier.isSubscribed(GROUP_CASE, SERVICE_NAME_CASE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOnEvent() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
List<String> clusters = Collections.singletonList(CLUSTER_STR_CASE);
|
||||
NamingSelector selector = NamingSelectorFactory.newClusterSelector(clusters);
|
||||
EventListener listener = Mockito.mock(EventListener.class);
|
||||
|
||||
instancesChangeNotifier.registerListener(group, name, clusters, listener);
|
||||
InstancesChangeEvent event1 = Mockito.mock(InstancesChangeEvent.class);
|
||||
when(event1.getClusters()).thenReturn(clusters);
|
||||
when(event1.getGroupName()).thenReturn(group);
|
||||
when(event1.getServiceName()).thenReturn(name);
|
||||
|
||||
NamingSelectorWrapper wrapper = new NamingSelectorWrapper(SERVICE_NAME_CASE, GROUP_CASE, CLUSTER_STR_CASE,
|
||||
selector, listener);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE, wrapper);
|
||||
Instance instance = new Instance();
|
||||
InstancesDiff diff = new InstancesDiff(null, Collections.singletonList(instance), null);
|
||||
instance.setClusterName(CLUSTER_STR_CASE);
|
||||
InstancesChangeEvent event1 = new InstancesChangeEvent(null, SERVICE_NAME_CASE, GROUP_CASE, CLUSTER_STR_CASE,
|
||||
Collections.emptyList(), diff);
|
||||
instancesChangeNotifier.onEvent(event1);
|
||||
Mockito.verify(listener, times(1)).onEvent(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOnEventWithoutListener() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeEvent event1 = Mockito.mock(InstancesChangeEvent.class);
|
||||
when(event1.getClusters()).thenReturn(clusters);
|
||||
when(event1.getGroupName()).thenReturn(group);
|
||||
when(event1.getServiceName()).thenReturn(name);
|
||||
when(event1.getClusters()).thenReturn(CLUSTER_STR_CASE);
|
||||
when(event1.getGroupName()).thenReturn(GROUP_CASE);
|
||||
when(event1.getServiceName()).thenReturn(SERVICE_NAME_CASE);
|
||||
EventListener listener = Mockito.mock(EventListener.class);
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
instancesChangeNotifier.registerListener(group, name + "c", clusters, listener);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE + "c", new NamingSelectorWrapper(
|
||||
NamingSelectorFactory.newClusterSelector(Collections.singletonList(CLUSTER_STR_CASE)), listener));
|
||||
instancesChangeNotifier.onEvent(event1);
|
||||
Mockito.verify(listener, never()).onEvent(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOnEventByExecutor() {
|
||||
String eventScope = "scope-001";
|
||||
String group = "a";
|
||||
String name = "b";
|
||||
String clusters = "c";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
AbstractEventListener listener = Mockito.mock(AbstractEventListener.class);
|
||||
Executor executor = mock(Executor.class);
|
||||
when(listener.getExecutor()).thenReturn(executor);
|
||||
|
||||
instancesChangeNotifier.registerListener(group, name, clusters, listener);
|
||||
InstancesChangeEvent event1 = Mockito.mock(InstancesChangeEvent.class);
|
||||
when(event1.getClusters()).thenReturn(clusters);
|
||||
when(event1.getGroupName()).thenReturn(group);
|
||||
when(event1.getServiceName()).thenReturn(name);
|
||||
|
||||
instancesChangeNotifier.onEvent(event1);
|
||||
instancesChangeNotifier.registerListener(GROUP_CASE, SERVICE_NAME_CASE,
|
||||
new NamingSelectorWrapper(new DefaultNamingSelector(instance -> true), listener));
|
||||
InstancesDiff instancesDiff = new InstancesDiff();
|
||||
instancesDiff.setRemovedInstances(Collections.singletonList(new Instance()));
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(EVENT_SCOPE_CASE, SERVICE_NAME_CASE, GROUP_CASE,
|
||||
CLUSTER_STR_CASE, new ArrayList<>(), instancesDiff);
|
||||
instancesChangeNotifier.onEvent(event);
|
||||
Mockito.verify(executor).execute(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSubscribeType() {
|
||||
String eventScope = "scope-001";
|
||||
InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(eventScope);
|
||||
assertEquals(InstancesChangeEvent.class, instancesChangeNotifier.subscribeType());
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.event;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.builder.InstanceBuilder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class InstancesDiffTest {
|
||||
|
||||
@Test
|
||||
public void testGetDiff() {
|
||||
String serviceName = "testService";
|
||||
Instance addedIns = InstanceBuilder.newBuilder().setServiceName(serviceName).setClusterName("a").build();
|
||||
Instance removedIns = InstanceBuilder.newBuilder().setServiceName(serviceName).setClusterName("b").build();
|
||||
Instance modifiedIns = InstanceBuilder.newBuilder().setServiceName(serviceName).setClusterName("c").build();
|
||||
|
||||
InstancesDiff instancesDiff = new InstancesDiff();
|
||||
instancesDiff.setAddedInstances(Collections.singletonList(addedIns));
|
||||
instancesDiff.setRemovedInstances(Collections.singletonList(removedIns));
|
||||
instancesDiff.setModifiedInstances(Collections.singletonList(modifiedIns));
|
||||
|
||||
Assert.assertTrue(instancesDiff.hasDifferent());
|
||||
Assert.assertTrue(instancesDiff.isAdded());
|
||||
Assert.assertTrue(instancesDiff.isRemoved());
|
||||
Assert.assertTrue(instancesDiff.isModified());
|
||||
Assert.assertEquals(addedIns, instancesDiff.getAddedInstances().get(0));
|
||||
Assert.assertEquals(removedIns, instancesDiff.getRemovedInstances().get(0));
|
||||
Assert.assertEquals(modifiedIns, instancesDiff.getModifiedInstances().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithFullConstructor() {
|
||||
Random random = new Random();
|
||||
int addedCount = random.nextInt(32) + 1;
|
||||
int removedCount = random.nextInt(32) + 1;
|
||||
int modifiedCount = random.nextInt(32) + 1;
|
||||
InstancesDiff instancesDiff = new InstancesDiff(getInstanceList(addedCount), getInstanceList(removedCount),
|
||||
getInstanceList(modifiedCount));
|
||||
|
||||
Assert.assertTrue(instancesDiff.hasDifferent());
|
||||
Assert.assertTrue(instancesDiff.isAdded());
|
||||
Assert.assertTrue(instancesDiff.isRemoved());
|
||||
Assert.assertTrue(instancesDiff.isModified());
|
||||
Assert.assertEquals(addedCount, instancesDiff.getAddedInstances().size());
|
||||
Assert.assertEquals(removedCount, instancesDiff.getRemovedInstances().size());
|
||||
Assert.assertEquals(modifiedCount, instancesDiff.getModifiedInstances().size());
|
||||
instancesDiff.getAddedInstances().clear();
|
||||
instancesDiff.getRemovedInstances().clear();
|
||||
instancesDiff.getModifiedInstances().clear();
|
||||
Assert.assertFalse(instancesDiff.hasDifferent());
|
||||
Assert.assertFalse(instancesDiff.hasDifferent());
|
||||
Assert.assertFalse(instancesDiff.isAdded());
|
||||
Assert.assertFalse(instancesDiff.isRemoved());
|
||||
Assert.assertFalse(instancesDiff.isModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithNoConstructor() {
|
||||
Random random = new Random();
|
||||
int addedCount = random.nextInt(32) + 1;
|
||||
int removedCount = random.nextInt(32) + 1;
|
||||
int modifiedCount = random.nextInt(32) + 1;
|
||||
InstancesDiff instancesDiff = new InstancesDiff();
|
||||
instancesDiff.setAddedInstances(getInstanceList(addedCount));
|
||||
instancesDiff.setRemovedInstances(getInstanceList(removedCount));
|
||||
instancesDiff.setModifiedInstances(getInstanceList(modifiedCount));
|
||||
|
||||
Assert.assertTrue(instancesDiff.hasDifferent());
|
||||
Assert.assertEquals(addedCount, instancesDiff.getAddedInstances().size());
|
||||
Assert.assertEquals(removedCount, instancesDiff.getRemovedInstances().size());
|
||||
Assert.assertEquals(modifiedCount, instancesDiff.getModifiedInstances().size());
|
||||
instancesDiff.getAddedInstances().clear();
|
||||
instancesDiff.getRemovedInstances().clear();
|
||||
instancesDiff.getModifiedInstances().clear();
|
||||
Assert.assertFalse(instancesDiff.hasDifferent());
|
||||
Assert.assertFalse(instancesDiff.isAdded());
|
||||
Assert.assertFalse(instancesDiff.isRemoved());
|
||||
Assert.assertFalse(instancesDiff.isModified());
|
||||
}
|
||||
|
||||
private static List<Instance> getInstanceList(int count) {
|
||||
ArrayList<Instance> list = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
list.add(new Instance());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.listener;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class NamingChangeEventTest {
|
||||
|
||||
private MockNamingEventListener eventListener;
|
||||
|
||||
private InstancesDiff instancesDiff;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
eventListener = new MockNamingEventListener();
|
||||
instancesDiff = new InstancesDiff();
|
||||
instancesDiff.setAddedInstances(Arrays.asList(new Instance(), new Instance(), new Instance()));
|
||||
instancesDiff.setRemovedInstances(Arrays.asList(new Instance(), new Instance()));
|
||||
instancesDiff.setModifiedInstances(Arrays.asList(new Instance()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamingChangeEventWithSimpleConstructor() {
|
||||
NamingChangeEvent event = new NamingChangeEvent("serviceName", Collections.EMPTY_LIST, instancesDiff);
|
||||
assertEquals("serviceName", event.getServiceName());
|
||||
assertNull(event.getGroupName());
|
||||
assertNull(event.getClusters());
|
||||
assertTrue(event.getInstances().isEmpty());
|
||||
assertTrue(event.isAdded());
|
||||
assertEquals(3, event.getAddedInstances().size());
|
||||
assertTrue(event.isRemoved());
|
||||
assertEquals(2, event.getRemovedInstances().size());
|
||||
assertTrue(event.isModified());
|
||||
assertEquals(1, event.getModifiedInstances().size());
|
||||
eventListener.onEvent(event);
|
||||
assertNull(event.getServiceName());
|
||||
assertNull(event.getGroupName());
|
||||
assertNull(event.getClusters());
|
||||
assertNull(event.getInstances());
|
||||
assertFalse(event.isAdded());
|
||||
assertEquals(0, event.getAddedInstances().size());
|
||||
assertFalse(event.isRemoved());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
assertFalse(event.isModified());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamingChangeEventWithFullConstructor() {
|
||||
NamingChangeEvent event = new NamingChangeEvent("serviceName", "group", "clusters", Collections.EMPTY_LIST,
|
||||
instancesDiff);
|
||||
assertEquals("serviceName", event.getServiceName());
|
||||
assertEquals("group", event.getGroupName());
|
||||
assertEquals("clusters", event.getClusters());
|
||||
assertTrue(event.getInstances().isEmpty());
|
||||
assertTrue(event.isAdded());
|
||||
assertEquals(3, event.getAddedInstances().size());
|
||||
assertTrue(event.isRemoved());
|
||||
assertEquals(2, event.getRemovedInstances().size());
|
||||
assertTrue(event.isModified());
|
||||
assertEquals(1, event.getModifiedInstances().size());
|
||||
eventListener.onEvent(event);
|
||||
assertNull(event.getServiceName());
|
||||
assertNull(event.getGroupName());
|
||||
assertNull(event.getClusters());
|
||||
assertNull(event.getInstances());
|
||||
assertFalse(event.isAdded());
|
||||
assertEquals(0, event.getAddedInstances().size());
|
||||
assertFalse(event.isRemoved());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
assertFalse(event.isModified());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetChanges() {
|
||||
NamingChangeEvent event = new NamingChangeEvent("serviceName", Collections.EMPTY_LIST, instancesDiff);
|
||||
assertTrue(event.isAdded());
|
||||
assertEquals(3, event.getAddedInstances().size());
|
||||
event.getAddedInstances().clear();
|
||||
assertFalse(event.isAdded());
|
||||
assertEquals(0, event.getAddedInstances().size());
|
||||
|
||||
assertTrue(event.isRemoved());
|
||||
assertEquals(2, event.getRemovedInstances().size());
|
||||
event.getRemovedInstances().clear();
|
||||
assertFalse(event.isRemoved());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
|
||||
assertTrue(event.isModified());
|
||||
assertEquals(1, event.getModifiedInstances().size());
|
||||
event.getModifiedInstances().clear();
|
||||
assertFalse(event.isModified());
|
||||
assertEquals(0, event.getRemovedInstances().size());
|
||||
}
|
||||
|
||||
private static class MockNamingEventListener extends AbstractNamingChangeListener {
|
||||
|
||||
@Override
|
||||
public void onChange(NamingChangeEvent event) {
|
||||
assertNull(getExecutor());
|
||||
event.setServiceName(null);
|
||||
event.setGroupName(null);
|
||||
event.setClusters(null);
|
||||
event.setInstances(null);
|
||||
event.getAddedInstances().clear();
|
||||
event.getRemovedInstances().clear();
|
||||
event.getModifiedInstances().clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingContext;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingResult;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DefaultNamingSelectorTest {
|
||||
|
||||
@Test
|
||||
public void testSelect() {
|
||||
DefaultNamingSelector namingSelector = new DefaultNamingSelector(Instance::isHealthy);
|
||||
Random random = new Random();
|
||||
int total = random.nextInt(32) + 1;
|
||||
int health = random.nextInt(total);
|
||||
|
||||
NamingContext namingContext = getMockNamingContext(total, health);
|
||||
NamingResult result = namingSelector.select(namingContext);
|
||||
|
||||
assertEquals(health, result.getResult().size());
|
||||
result.getResult().forEach(ins -> assertTrue(ins.isHealthy()));
|
||||
}
|
||||
|
||||
private NamingContext getMockNamingContext(int total, int health) {
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(getInstance(total, health));
|
||||
return namingContext;
|
||||
}
|
||||
|
||||
private List<Instance> getInstance(int total, int health) {
|
||||
List<Instance> list = new ArrayList<>(total);
|
||||
for (int i = 0; i < total; i++) {
|
||||
Instance instance = new Instance();
|
||||
instance.setHealthy(false);
|
||||
list.add(instance);
|
||||
}
|
||||
|
||||
for (int i = 0; i < health; i++) {
|
||||
list.get(i).setHealthy(true);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import com.alibaba.nacos.client.naming.listener.AbstractNamingChangeListener;
|
||||
import com.alibaba.nacos.client.naming.listener.NamingChangeEvent;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
public class NamingListenerInvokerTest {
|
||||
|
||||
@Test
|
||||
public void testEventListener() {
|
||||
EventListener listener = mock(EventListener.class);
|
||||
NamingListenerInvoker listenerInvoker = new NamingListenerInvoker(listener);
|
||||
NamingEvent event = new NamingEvent("serviceName", Collections.emptyList());
|
||||
listenerInvoker.invoke(event);
|
||||
verify(listener).onEvent(event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractEventListener() {
|
||||
AbstractEventListener listener = mock(AbstractEventListener.class);
|
||||
NamingListenerInvoker listenerInvoker = new NamingListenerInvoker(listener);
|
||||
NamingEvent event = new NamingEvent("serviceName", Collections.emptyList());
|
||||
listenerInvoker.invoke(event);
|
||||
verify(listener).getExecutor();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractNamingChaneEventListener() {
|
||||
AbstractNamingChangeListener listener = spy(AbstractNamingChangeListener.class);
|
||||
NamingListenerInvoker listenerInvoker = new NamingListenerInvoker(listener);
|
||||
NamingChangeEvent event = new NamingChangeEvent("serviceName", Collections.emptyList(), new InstancesDiff());
|
||||
listenerInvoker.invoke(event);
|
||||
verify(listener).onChange(event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
EventListener listener1 = mock(EventListener.class);
|
||||
EventListener listener2 = mock(EventListener.class);
|
||||
NamingListenerInvoker invoker1 = new NamingListenerInvoker(listener1);
|
||||
NamingListenerInvoker invoker2 = new NamingListenerInvoker(listener1);
|
||||
NamingListenerInvoker invoker3 = new NamingListenerInvoker(listener2);
|
||||
assertEquals(invoker1.hashCode(), invoker2.hashCode());
|
||||
assertEquals(invoker1, invoker2);
|
||||
assertNotEquals(invoker1.hashCode(), invoker3.hashCode());
|
||||
assertNotEquals(invoker1, invoker3);
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingContext;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingResult;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class NamingSelectorFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testNewClusterSelector1() {
|
||||
Instance ins1 = new Instance();
|
||||
ins1.setClusterName("a");
|
||||
Instance ins2 = new Instance();
|
||||
ins2.setClusterName("b");
|
||||
Instance ins3 = new Instance();
|
||||
ins3.setClusterName("c");
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
NamingSelector namingSelector1 = NamingSelectorFactory.newClusterSelector(Collections.singletonList("a"));
|
||||
NamingResult result1 = namingSelector1.select(namingContext);
|
||||
assertEquals("a", result1.getResult().get(0).getClusterName());
|
||||
|
||||
NamingSelector namingSelector2 = NamingSelectorFactory.newClusterSelector(Collections.emptyList());
|
||||
NamingResult result2 = namingSelector2.select(namingContext);
|
||||
assertEquals(3, result2.getResult().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewClusterSelector2() {
|
||||
NamingSelector namingSelector1 = NamingSelectorFactory.newClusterSelector(Arrays.asList("a", "b", "c"));
|
||||
NamingSelector namingSelector2 = NamingSelectorFactory.newClusterSelector(Arrays.asList("c", "b", "a"));
|
||||
NamingSelector namingSelector3 = NamingSelectorFactory.newClusterSelector(Arrays.asList("a", "b", "c", "c"));
|
||||
NamingSelector namingSelector4 = NamingSelectorFactory.newClusterSelector(Arrays.asList("d", "e"));
|
||||
|
||||
assertEquals(namingSelector1, namingSelector2);
|
||||
assertEquals(namingSelector1, namingSelector3);
|
||||
assertNotEquals(namingSelector1, namingSelector4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewIpSelector() {
|
||||
Instance ins1 = new Instance();
|
||||
ins1.setIp("172.18.137.120");
|
||||
Instance ins2 = new Instance();
|
||||
ins2.setIp("172.18.137.121");
|
||||
Instance ins3 = new Instance();
|
||||
ins3.setIp("172.18.136.111");
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
NamingSelector ipSelector = NamingSelectorFactory.newIpSelector("^172\\.18\\.137.*");
|
||||
NamingResult result = ipSelector.select(namingContext);
|
||||
List<Instance> list = result.getResult();
|
||||
|
||||
assertEquals(2, list.size());
|
||||
assertEquals(ins1.getIp(), list.get(0).getIp());
|
||||
assertEquals(ins2.getIp(), list.get(1).getIp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewMetadataSelector() {
|
||||
Instance ins1 = new Instance();
|
||||
ins1.addMetadata("a", "1");
|
||||
ins1.addMetadata("b", "2");
|
||||
Instance ins2 = new Instance();
|
||||
ins2.addMetadata("a", "1");
|
||||
Instance ins3 = new Instance();
|
||||
ins3.addMetadata("b", "2");
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
NamingSelector metadataSelector = NamingSelectorFactory.newMetadataSelector(new HashMap() {
|
||||
{
|
||||
put("a", "1");
|
||||
put("b", "2");
|
||||
}
|
||||
});
|
||||
List<Instance> result = metadataSelector.select(namingContext).getResult();
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(ins1, result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewMetadataSelector2() {
|
||||
Instance ins1 = new Instance();
|
||||
ins1.addMetadata("a", "1");
|
||||
ins1.addMetadata("c", "3");
|
||||
Instance ins2 = new Instance();
|
||||
ins2.addMetadata("b", "2");
|
||||
Instance ins3 = new Instance();
|
||||
ins3.addMetadata("c", "3");
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
NamingSelector metadataSelector = NamingSelectorFactory.newMetadataSelector(new HashMap() {
|
||||
{
|
||||
put("a", "1");
|
||||
put("b", "2");
|
||||
}
|
||||
}, true);
|
||||
List<Instance> result = metadataSelector.select(namingContext).getResult();
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertEquals(ins1, result.get(0));
|
||||
assertEquals(ins2, result.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHealthSelector() {
|
||||
Instance ins1 = new Instance();
|
||||
Instance ins2 = new Instance();
|
||||
Instance ins3 = new Instance();
|
||||
ins3.setHealthy(false);
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
List<Instance> result = NamingSelectorFactory.HEALTHY_SELECTOR.select(namingContext).getResult();
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.contains(ins1));
|
||||
assertTrue(result.contains(ins2));
|
||||
assertTrue(result.get(0).isHealthy());
|
||||
assertTrue(result.get(1).isHealthy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptySelector() {
|
||||
Instance ins1 = new Instance();
|
||||
Instance ins2 = new Instance();
|
||||
Instance ins3 = new Instance();
|
||||
|
||||
NamingContext namingContext = mock(NamingContext.class);
|
||||
when(namingContext.getInstances()).thenReturn(Arrays.asList(ins1, ins2, ins3));
|
||||
|
||||
List<Instance> result = NamingSelectorFactory.EMPTY_SELECTOR.select(namingContext).getResult();
|
||||
|
||||
assertEquals(3, result.size());
|
||||
assertTrue(result.contains(ins1));
|
||||
assertTrue(result.contains(ins2));
|
||||
assertTrue(result.contains(ins3));
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.naming.selector;
|
||||
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
|
||||
import com.alibaba.nacos.client.naming.event.InstancesDiff;
|
||||
import com.alibaba.nacos.client.naming.listener.NamingChangeEvent;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
public class NamingSelectorWrapperTest {
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
EventListener listener = mock(EventListener.class);
|
||||
NamingSelector selector1 = mock(NamingSelector.class);
|
||||
NamingSelector selector2 = mock(NamingSelector.class);
|
||||
NamingSelectorWrapper sw1 = new NamingSelectorWrapper(selector1, listener);
|
||||
NamingSelectorWrapper sw2 = new NamingSelectorWrapper(selector2, listener);
|
||||
NamingSelectorWrapper sw3 = new NamingSelectorWrapper(selector1, listener);
|
||||
|
||||
assertNotEquals(sw1.hashCode(), sw2.hashCode());
|
||||
assertEquals(sw1.hashCode(), sw3.hashCode());
|
||||
assertNotEquals(sw1, sw2);
|
||||
assertEquals(sw1, sw3);
|
||||
|
||||
Set<NamingSelectorWrapper> set = new HashSet<>();
|
||||
set.add(sw1);
|
||||
assertFalse(set.contains(sw2));
|
||||
assertTrue(set.contains(sw3));
|
||||
assertTrue(set.add(sw2));
|
||||
assertFalse(set.add(sw3));
|
||||
assertTrue(set.remove(sw3));
|
||||
|
||||
assertEquals(sw1, new NamingSelectorWrapper("a", "b", "c", selector1, listener));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectable() {
|
||||
NamingSelectorWrapper selectorWrapper = new NamingSelectorWrapper(null, null);
|
||||
assertFalse(selectorWrapper.isSelectable(null));
|
||||
InstancesChangeEvent event1 = new InstancesChangeEvent(null, null, null, null, null, null);
|
||||
assertFalse(selectorWrapper.isSelectable(event1));
|
||||
InstancesChangeEvent event2 = new InstancesChangeEvent(null, null, null, null, null, new InstancesDiff());
|
||||
assertFalse(selectorWrapper.isSelectable(event2));
|
||||
InstancesChangeEvent event3 = new InstancesChangeEvent(null, null, null, null, Collections.emptyList(), null);
|
||||
assertFalse(selectorWrapper.isSelectable(event3));
|
||||
InstancesChangeEvent event4 = new InstancesChangeEvent(null, null, null, null, Collections.emptyList(),
|
||||
new InstancesDiff());
|
||||
assertTrue(selectorWrapper.isSelectable(event4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallable() {
|
||||
NamingSelectorWrapper selectorWrapper = new NamingSelectorWrapper(null, null);
|
||||
InstancesDiff instancesDiff = new InstancesDiff(null, Collections.singletonList(new Instance()), null);
|
||||
NamingChangeEvent changeEvent = new NamingChangeEvent("serviceName", Collections.emptyList(), instancesDiff);
|
||||
assertTrue(selectorWrapper.isCallable(changeEvent));
|
||||
changeEvent.getRemovedInstances().clear();
|
||||
assertFalse(selectorWrapper.isCallable(changeEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyListener() {
|
||||
EventListener listener = mock(EventListener.class);
|
||||
NamingSelectorWrapper selectorWrapper = new NamingSelectorWrapper(
|
||||
new DefaultNamingSelector(Instance::isHealthy), listener);
|
||||
InstancesDiff diff = new InstancesDiff(null, Collections.singletonList(new Instance()), null);
|
||||
InstancesChangeEvent event = new InstancesChangeEvent(null, "serviceName", "groupName", "clusters",
|
||||
Collections.emptyList(), diff);
|
||||
selectorWrapper.notifyListener(event);
|
||||
verify(listener).onEvent(argThat(Objects::nonNull));
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.selector;
|
||||
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorWrapper;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class SelectorManagerTest {
|
||||
|
||||
@Test
|
||||
public void testCurd() {
|
||||
SelectorManager<NamingSelectorWrapper> selectorManager = new SelectorManager<>();
|
||||
String subId = "subId";
|
||||
NamingSelectorWrapper sw = mock(NamingSelectorWrapper.class);
|
||||
selectorManager.addSelectorWrapper(subId, sw);
|
||||
assertTrue(selectorManager.getSelectorWrappers(subId).contains(sw));
|
||||
selectorManager.removeSelectorWrapper(subId, sw);
|
||||
assertTrue(selectorManager.getSelectorWrappers(subId).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubInfo() {
|
||||
SelectorManager<NamingSelectorWrapper> selectorManager = new SelectorManager<>();
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int i = 0; i < 64; i++) {
|
||||
list.add(generateRandomString(2, 32));
|
||||
}
|
||||
|
||||
for (String subId : list) {
|
||||
selectorManager.addSelectorWrapper(subId, mock(NamingSelectorWrapper.class));
|
||||
assertTrue(selectorManager.isSubscribed(subId));
|
||||
}
|
||||
|
||||
Set<String> subsSet = selectorManager.getSubscriptions();
|
||||
for (String subId : subsSet) {
|
||||
assertTrue(list.contains(subId));
|
||||
}
|
||||
|
||||
for (String subId : list) {
|
||||
selectorManager.removeSubscription(subId);
|
||||
assertFalse(selectorManager.isSubscribed(subId));
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateRandomString(int minLength, int maxLength) {
|
||||
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
Random random = new Random();
|
||||
int length = random.nextInt(maxLength - minLength + 1) + minLength;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = random.nextInt(characters.length());
|
||||
char randomChar = characters.charAt(index);
|
||||
sb.append(randomChar);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.test.naming;
|
||||
|
||||
import com.alibaba.nacos.Nacos;
|
||||
import com.alibaba.nacos.api.naming.NamingFactory;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.listener.Event;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.client.naming.selector.DefaultNamingSelector;
|
||||
import com.alibaba.nacos.client.naming.selector.NamingSelectorFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author lideyou
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Nacos.class, properties = {
|
||||
"server.servlet.context-path=/nacos"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
public class SubscribeSelector_ITCase extends NamingBase {
|
||||
|
||||
private NamingService naming;
|
||||
|
||||
private NamingSelector selector = new DefaultNamingSelector(instance -> instance.getIp().startsWith("172.18.137"));
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
instances.clear();
|
||||
if (naming == null) {
|
||||
naming = NamingFactory.createNamingService("127.0.0.1" + ":" + port);
|
||||
}
|
||||
}
|
||||
|
||||
private volatile List<Instance> instances = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Add IP and receive notification.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(timeout = 10000L)
|
||||
public void subscribeAdd() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
naming.subscribe(serviceName, selector, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
naming.registerInstance(serviceName, "172.18.137.1", TEST_PORT);
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete IP and receive notification.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(timeout = 10000L)
|
||||
public void subscribeDelete() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
naming.registerInstance(serviceName, "172.18.137.1", TEST_PORT, "c1");
|
||||
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
|
||||
naming.subscribe(serviceName, selector, new EventListener() {
|
||||
int index = 0;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
if (index == 0) {
|
||||
index++;
|
||||
return;
|
||||
}
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
}
|
||||
});
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
naming.deregisterInstance(serviceName, "172.18.137.1", TEST_PORT, "c1");
|
||||
|
||||
while (!instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(instances.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add non target IP and do not receive notification.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void subscribeOtherIp() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
naming.subscribe(serviceName, selector, new EventListener() {
|
||||
int index = 0;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
if (index == 0) {
|
||||
index++;
|
||||
return;
|
||||
}
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
}
|
||||
});
|
||||
|
||||
naming.registerInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
int i = 0;
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
if (i++ > 10) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.test.naming;
|
||||
|
||||
import com.alibaba.nacos.Nacos;
|
||||
@ -22,11 +23,12 @@ import com.alibaba.nacos.api.naming.listener.Event;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.client.naming.listener.AbstractNamingChangeListener;
|
||||
import com.alibaba.nacos.client.naming.listener.NamingChangeEvent;
|
||||
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.test.base.Params;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -42,6 +44,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by wangtong.wt on 2018/6/20.
|
||||
@ -50,14 +55,15 @@ import java.util.concurrent.TimeUnit;
|
||||
* @date 2018/6/20
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Nacos.class, properties = {"server.servlet.context-path=/nacos"},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
@SpringBootTest(classes = Nacos.class, properties = {
|
||||
"server.servlet.context-path=/nacos"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
public class Subscribe_ITCase extends NamingBase {
|
||||
|
||||
|
||||
private NamingService naming;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
instances.clear();
|
||||
@ -71,9 +77,9 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
String url = String.format("http://localhost:%d/", port);
|
||||
this.base = new URL(url);
|
||||
}
|
||||
|
||||
|
||||
private volatile List<Instance> instances = Collections.emptyList();
|
||||
|
||||
|
||||
/**
|
||||
* 添加IP,收到通知
|
||||
*
|
||||
@ -82,7 +88,7 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
@Test(timeout = 4 * TIME_OUT)
|
||||
public void subscribeAdd() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
@ -91,16 +97,16 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除IP,收到通知
|
||||
*
|
||||
@ -110,12 +116,12 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
public void subscribeDelete() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
|
||||
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
int index = 0;
|
||||
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (index == 0) {
|
||||
@ -127,18 +133,18 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
|
||||
naming.deregisterInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (!instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(instances.isEmpty());
|
||||
|
||||
assertTrue(instances.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加不可用IP,收到通知
|
||||
*
|
||||
@ -147,7 +153,7 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
@Test(timeout = 4 * TIME_OUT)
|
||||
public void subscribeUnhealthy() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
@ -156,21 +162,21 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
}
|
||||
|
||||
@Test(timeout = 4 * TIME_OUT)
|
||||
public void subscribeEmpty() throws Exception {
|
||||
|
||||
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
@ -179,32 +185,32 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
|
||||
assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
naming.deregisterInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (!instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
|
||||
Assert.assertEquals(0, instances.size());
|
||||
Assert.assertEquals(0, naming.getAllInstances(serviceName).size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void querySubscribers() throws Exception {
|
||||
|
||||
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
EventListener listener = new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
@ -213,30 +219,25 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
naming.subscribe(serviceName, listener);
|
||||
|
||||
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
|
||||
|
||||
ResponseEntity<String> response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service/subscribers",
|
||||
Params.newParams()
|
||||
.appendParam("serviceName", serviceName)
|
||||
.appendParam("pageNo", "1")
|
||||
.appendParam("pageSize", "10")
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.GET);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
Params.newParams().appendParam("serviceName", serviceName).appendParam("pageNo", "1")
|
||||
.appendParam("pageSize", "10").done(), String.class, HttpMethod.GET);
|
||||
assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
JsonNode body = JacksonUtils.toObj(response.getBody());
|
||||
|
||||
|
||||
Assert.assertEquals(1, body.get("subscribers").size());
|
||||
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("namingRequestTimeout", "300000");
|
||||
properties.setProperty("serverAddr", "127.0.0.1" + ":" + port);
|
||||
NamingService naming2 = NamingFactory.createNamingService(properties);
|
||||
|
||||
|
||||
naming2.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
@ -245,21 +246,16 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
|
||||
|
||||
response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service/subscribers",
|
||||
Params.newParams()
|
||||
.appendParam("serviceName", serviceName)
|
||||
.appendParam("pageNo", "1")
|
||||
.appendParam("pageSize", "10")
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.GET);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
Params.newParams().appendParam("serviceName", serviceName).appendParam("pageNo", "1")
|
||||
.appendParam("pageSize", "10").done(), String.class, HttpMethod.GET);
|
||||
assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
body = JacksonUtils.toObj(response.getBody());
|
||||
|
||||
|
||||
// server will remove duplicate subscriber by ip port service app and so on
|
||||
Assert.assertEquals(1, body.get("subscribers").size());
|
||||
}
|
||||
@ -294,7 +290,7 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
concurrentHashSet1.addAll(((NamingEvent) event).getInstances());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
naming1.registerInstance(serviceName, "1.1.1.1", TEST_PORT, "c1");
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
@ -302,11 +298,73 @@ public class Subscribe_ITCase extends NamingBase {
|
||||
}
|
||||
|
||||
try {
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming1.getAllInstances(serviceName)));
|
||||
assertTrue(verifyInstanceList(instances, naming1.getAllInstances(serviceName)));
|
||||
Assert.assertEquals(0, concurrentHashSet1.size());
|
||||
} finally {
|
||||
naming1.shutDown();
|
||||
naming2.shutDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subscribeUsingAbstractNamingChangeListener() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
naming.subscribe(serviceName, new AbstractNamingChangeListener() {
|
||||
@Override
|
||||
public void onChange(NamingChangeEvent event) {
|
||||
System.out.println(event.getServiceName());
|
||||
System.out.println(event.getInstances());
|
||||
instances = event.getInstances();
|
||||
assertTrue(event.isAdded());
|
||||
}
|
||||
});
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerFirstCallback() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
count.incrementAndGet();
|
||||
}
|
||||
});
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
naming.subscribe(serviceName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
count.incrementAndGet();
|
||||
}
|
||||
});
|
||||
|
||||
int i = 0;
|
||||
while (count.get() < 2) {
|
||||
Thread.sleep(1000L);
|
||||
if (i++ > 10) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.test.naming;
|
||||
|
||||
import com.alibaba.nacos.Nacos;
|
||||
@ -22,7 +23,8 @@ import com.alibaba.nacos.api.naming.listener.Event;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import com.alibaba.nacos.api.naming.selector.NamingSelector;
|
||||
import com.alibaba.nacos.client.naming.selector.DefaultNamingSelector;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -35,7 +37,9 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.alibaba.nacos.test.naming.NamingBase.*;
|
||||
import static com.alibaba.nacos.test.naming.NamingBase.TEST_PORT;
|
||||
import static com.alibaba.nacos.test.naming.NamingBase.randomDomainName;
|
||||
import static com.alibaba.nacos.test.naming.NamingBase.verifyInstanceList;
|
||||
|
||||
/**
|
||||
* Created by wangtong.wt on 2018/6/20.
|
||||
@ -44,57 +48,59 @@ import static com.alibaba.nacos.test.naming.NamingBase.*;
|
||||
* @date 2018/6/20
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Nacos.class, properties = {"server.servlet.context-path=/nacos"},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
@SpringBootTest(classes = Nacos.class, properties = {
|
||||
"server.servlet.context-path=/nacos"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
public class Unsubscribe_ITCase {
|
||||
|
||||
|
||||
private NamingService naming;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
instances = Collections.emptyList();
|
||||
if (naming == null) {
|
||||
//TimeUnit.SECONDS.sleep(10);
|
||||
naming = NamingFactory.createNamingService("127.0.0.1"+":"+port);
|
||||
naming = NamingFactory.createNamingService("127.0.0.1" + ":" + port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private volatile List<Instance> instances = Collections.emptyList();
|
||||
|
||||
|
||||
/**
|
||||
* 取消订阅,添加IP,不会收到通知
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void unsubscribe() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
EventListener listener = new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent)event).getServiceName());
|
||||
System.out.println(((NamingEvent)event).getInstances());
|
||||
instances = ((NamingEvent)event).getInstances();
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
naming.subscribe(serviceName, listener);
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
|
||||
naming.unsubscribe(serviceName, listener);
|
||||
|
||||
|
||||
instances = Collections.emptyList();
|
||||
naming.registerInstance(serviceName, "127.0.0.2", TEST_PORT, "c1");
|
||||
|
||||
|
||||
int i = 0;
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
@ -102,42 +108,43 @@ public class Unsubscribe_ITCase {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取消订阅,在指定cluster添加IP,不会收到通知
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void unsubscribeCluster() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
|
||||
EventListener listener = new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent)event).getServiceName());
|
||||
System.out.println(((NamingEvent)event).getInstances());
|
||||
instances = ((NamingEvent)event).getInstances();
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
naming.subscribe(serviceName, Arrays.asList("c1"), listener);
|
||||
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT, "c1");
|
||||
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
|
||||
naming.unsubscribe(serviceName, Arrays.asList("c1"), listener);
|
||||
|
||||
|
||||
instances = Collections.emptyList();
|
||||
naming.registerInstance(serviceName, "127.0.0.2", TEST_PORT, "c1");
|
||||
|
||||
|
||||
int i = 0;
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
@ -145,8 +152,54 @@ public class Unsubscribe_ITCase {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取消订阅,添加选择器范围 IP,不会收到通知
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void unsubscribeSelector() throws Exception {
|
||||
String serviceName = randomDomainName();
|
||||
|
||||
EventListener listener = new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
System.out.println(((NamingEvent) event).getServiceName());
|
||||
System.out.println(((NamingEvent) event).getInstances());
|
||||
instances = ((NamingEvent) event).getInstances();
|
||||
}
|
||||
};
|
||||
|
||||
NamingSelector selector = new DefaultNamingSelector(instance -> instance.getIp().startsWith("127.0.0"));
|
||||
|
||||
naming.subscribe(serviceName, selector, listener);
|
||||
|
||||
naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT);
|
||||
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Assert.assertTrue(verifyInstanceList(instances, naming.getAllInstances(serviceName)));
|
||||
|
||||
naming.unsubscribe(serviceName, selector, listener);
|
||||
|
||||
instances = Collections.emptyList();
|
||||
naming.registerInstance(serviceName, "127.0.0.2", TEST_PORT);
|
||||
|
||||
int i = 0;
|
||||
while (instances.isEmpty()) {
|
||||
Thread.sleep(1000L);
|
||||
if (i++ > 10) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user