| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.servicecomb.serviceregistry.registry.cache; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.function.Function; |
| |
| import org.apache.servicecomb.foundation.common.Holder; |
| import org.apache.servicecomb.registry.api.registry.FindInstancesResponse; |
| import org.apache.servicecomb.registry.api.registry.Microservice; |
| import org.apache.servicecomb.registry.api.registry.MicroserviceInstance; |
| import org.apache.servicecomb.registry.api.registry.MicroserviceInstances; |
| import org.apache.servicecomb.registry.consumer.MicroserviceInstancePing; |
| import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; |
| import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import mockit.Mock; |
| import mockit.MockUp; |
| import org.junit.jupiter.api.Assertions; |
| |
| public class RefreshableMicroserviceCacheTest { |
| |
| private final Holder<Function<Object[], MicroserviceInstances>> findServiceInstancesOprHolder = new Holder<>(); |
| |
| private ServiceRegistryClient srClient; |
| |
| private RefreshableMicroserviceCache microserviceCache; |
| |
| private List<MicroserviceInstance> pulledInstances = new ArrayList<>(); |
| |
| private Microservice consumerService; |
| |
| @Before |
| public void setUp() throws Exception { |
| srClient = new MockUp<ServiceRegistryClient>() { |
| @Mock |
| MicroserviceInstances findServiceInstances(String consumerId, String appId, String serviceName, |
| String versionRule, String revision) { |
| return findServiceInstancesOprHolder.value |
| .apply(new Object[] {consumerId, appId, serviceName, versionRule, revision}); |
| } |
| }.getMockInstance(); |
| consumerService = new Microservice(); |
| consumerService.setServiceId("consumerId"); |
| microserviceCache = new RefreshableMicroserviceCache( |
| consumerService, |
| MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(), |
| srClient, |
| false); |
| |
| findServiceInstancesOprHolder.value = params -> { |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setNeedRefresh(true); |
| microserviceInstances.setRevision("rev0"); |
| microserviceInstances.setMicroserviceNotExist(false); |
| |
| FindInstancesResponse instancesResponse = new FindInstancesResponse(); |
| instancesResponse.setInstances(pulledInstances); |
| microserviceInstances.setInstancesResponse(instancesResponse); |
| |
| return microserviceInstances; |
| }; |
| } |
| |
| @Test |
| public void forceRefresh() { |
| MicroserviceInstance microserviceInstance = new MicroserviceInstance(); |
| microserviceInstance.setInstanceId("instanceId00"); |
| ArrayList<MicroserviceInstance> instances = new ArrayList<>(); |
| instances.add(microserviceInstance); |
| findServiceInstancesOprHolder.value = params -> { |
| Assertions.assertEquals("consumerId", params[0]); |
| Assertions.assertEquals("app", params[1]); |
| Assertions.assertEquals("svc", params[2]); |
| Assertions.assertEquals("0.0.0.0+", params[3]); |
| Assertions.assertNull(params[4]); |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setNeedRefresh(true); |
| microserviceInstances.setRevision("rev2"); |
| microserviceInstances.setMicroserviceNotExist(false); |
| |
| FindInstancesResponse instancesResponse = new FindInstancesResponse(); |
| instancesResponse.setInstances(instances); |
| |
| microserviceInstances.setInstancesResponse(instancesResponse); |
| return microserviceInstances; |
| }; |
| |
| microserviceCache.revisionId = "rev"; |
| microserviceCache.forceRefresh(); |
| |
| Assertions.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); |
| List<MicroserviceInstance> cachedInstances = microserviceCache.getInstances(); |
| Assertions.assertEquals(1, cachedInstances.size()); |
| MicroserviceInstance instance = cachedInstances.iterator().next(); |
| Assertions.assertEquals("instanceId00", instance.getInstanceId()); |
| Assertions.assertEquals("rev2", microserviceCache.getRevisionId()); |
| } |
| |
| @Test |
| public void refresh() { |
| ArrayList<MicroserviceInstance> instances = new ArrayList<>(); |
| findServiceInstancesOprHolder.value = params -> { |
| Assertions.assertEquals("consumerId", params[0]); |
| Assertions.assertEquals("app", params[1]); |
| Assertions.assertEquals("svc", params[2]); |
| Assertions.assertEquals("0.0.0.0+", params[3]); |
| Assertions.assertNull(params[4]); |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setNeedRefresh(true); |
| microserviceInstances.setRevision("rev0"); |
| microserviceInstances.setMicroserviceNotExist(false); |
| |
| FindInstancesResponse instancesResponse = new FindInstancesResponse(); |
| instancesResponse.setInstances(instances); |
| |
| microserviceInstances.setInstancesResponse(instancesResponse); |
| return microserviceInstances; |
| }; |
| |
| // at the beginning, no instances in cache |
| List<MicroserviceInstance> cachedInstances = microserviceCache.getInstances(); |
| Assertions.assertEquals(0, cachedInstances.size()); |
| Assertions.assertNull(microserviceCache.getRevisionId()); |
| |
| // find 1 instance from sc |
| MicroserviceInstance microserviceInstance = new MicroserviceInstance(); |
| instances.add(microserviceInstance); |
| microserviceInstance.setInstanceId("instanceId00"); |
| |
| microserviceCache.refresh(); |
| Assertions.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); |
| |
| cachedInstances = microserviceCache.getInstances(); |
| Assertions.assertEquals(1, cachedInstances.size()); |
| MicroserviceInstance instance = cachedInstances.iterator().next(); |
| Assertions.assertEquals("instanceId00", instance.getInstanceId()); |
| Assertions.assertEquals("rev0", microserviceCache.getRevisionId()); |
| |
| // 2nd time, find 2 instances, one of them is the old instance |
| MicroserviceInstance microserviceInstance1 = new MicroserviceInstance(); |
| instances.add(microserviceInstance1); |
| microserviceInstance1.setInstanceId("instanceId01"); |
| |
| findServiceInstancesOprHolder.value = params -> { |
| Assertions.assertEquals("consumerId", params[0]); |
| Assertions.assertEquals("app", params[1]); |
| Assertions.assertEquals("svc", params[2]); |
| Assertions.assertEquals("0.0.0.0+", params[3]); |
| Assertions.assertEquals("rev0", params[4]); |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setNeedRefresh(true); |
| microserviceInstances.setRevision("rev1"); |
| microserviceInstances.setMicroserviceNotExist(false); |
| |
| FindInstancesResponse instancesResponse = new FindInstancesResponse(); |
| instancesResponse.setInstances(instances); |
| |
| microserviceInstances.setInstancesResponse(instancesResponse); |
| return microserviceInstances; |
| }; |
| |
| microserviceCache.refresh(); |
| Assertions.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); |
| cachedInstances = microserviceCache.getInstances(); |
| Assertions.assertEquals(2, cachedInstances.size()); |
| Assertions.assertEquals("instanceId00", cachedInstances.get(0).getInstanceId()); |
| Assertions.assertEquals("instanceId01", cachedInstances.get(1).getInstanceId()); |
| } |
| |
| @Test |
| public void refresh_service_error() { |
| findServiceInstancesOprHolder.value = params -> null; |
| |
| List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances(); |
| |
| microserviceCache.refresh(); |
| Assertions.assertEquals(MicroserviceCacheStatus.CLIENT_ERROR, microserviceCache.getStatus()); |
| Assertions.assertSame(oldInstanceList, microserviceCache.getInstances()); |
| } |
| |
| @Test |
| public void refresh_service_not_exist() { |
| findServiceInstancesOprHolder.value = params -> { |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setMicroserviceNotExist(true); |
| return microserviceInstances; |
| }; |
| |
| List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances(); |
| |
| microserviceCache.refresh(); |
| Assertions.assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, microserviceCache.getStatus()); |
| Assertions.assertSame(oldInstanceList, microserviceCache.getInstances()); |
| } |
| |
| @Test |
| public void refresh_service_no_change() { |
| findServiceInstancesOprHolder.value = params -> { |
| MicroserviceInstances microserviceInstances = new MicroserviceInstances(); |
| microserviceInstances.setMicroserviceNotExist(false); |
| microserviceInstances.setNeedRefresh(false); |
| return microserviceInstances; |
| }; |
| |
| List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances(); |
| |
| microserviceCache.refresh(); |
| Assertions.assertEquals(MicroserviceCacheStatus.NO_CHANGE, microserviceCache.getStatus()); |
| Assertions.assertSame(oldInstanceList, microserviceCache.getInstances()); |
| } |
| |
| @Test |
| public void refresh_error_in_setInstances() { |
| microserviceCache = new RefreshableMicroserviceCache( |
| consumerService, |
| MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(), |
| srClient, |
| false) { |
| @Override |
| protected Set<MicroserviceInstance> mergeInstances(List<MicroserviceInstance> pulledInstances) { |
| throw new IllegalStateException("a mock exception"); |
| } |
| }; |
| |
| List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances(); |
| Assertions.assertEquals(MicroserviceCacheStatus.INIT, microserviceCache.getStatus()); |
| |
| microserviceCache.refresh(); |
| |
| Assertions.assertEquals(MicroserviceCacheStatus.SETTING_CACHE_ERROR, microserviceCache.getStatus()); |
| List<MicroserviceInstance> newInstanceList = microserviceCache.getInstances(); |
| Assertions.assertEquals(0, newInstanceList.size()); |
| Assertions.assertSame(oldInstanceList, newInstanceList); |
| } |
| |
| @Test |
| public void refresh_empty_instance_protection_disabled() { |
| microserviceCache.instances = new ArrayList<>(); |
| MicroserviceInstance instance0 = new MicroserviceInstance(); |
| instance0.setInstanceId("instanceId0"); |
| microserviceCache.instances.add(instance0); |
| |
| pulledInstances = new ArrayList<>(); |
| microserviceCache.refresh(); |
| |
| Assertions.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); |
| Assertions.assertEquals(0, microserviceCache.getInstances().size()); |
| } |
| |
| @Test |
| public void refresh_empty_instance_protection_enabled() { |
| microserviceCache.setEmptyInstanceProtectionEnabled(true); |
| microserviceCache.instancePing = new MicroserviceInstancePing() { |
| @Override |
| public int getOrder() { |
| return 0; |
| } |
| |
| @Override |
| public boolean ping(MicroserviceInstance instance) { |
| return true; |
| } |
| }; |
| microserviceCache.instances = new ArrayList<>(); |
| MicroserviceInstance instance0 = new MicroserviceInstance(); |
| instance0.setInstanceId("instanceId0"); |
| microserviceCache.instances.add(instance0); |
| |
| pulledInstances = new ArrayList<>(); |
| microserviceCache.refresh(); |
| |
| Assertions.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); |
| Assertions.assertEquals(1, microserviceCache.getInstances().size()); |
| Assertions.assertEquals("instanceId0", microserviceCache.getInstances().get(0).getInstanceId()); |
| } |
| |
| @Test |
| public void set_consumer_service_id() { |
| Holder<Integer> assertCounter = new Holder<>(0); |
| Function<Object[], MicroserviceInstances> preservedLogic = findServiceInstancesOprHolder.value; |
| findServiceInstancesOprHolder.value = params -> { |
| Assertions.assertEquals("consumerId", params[0]); |
| assertCounter.value++; |
| return preservedLogic.apply(params); |
| }; |
| microserviceCache.refresh(); |
| |
| consumerService.setServiceId("consumerId2"); |
| |
| findServiceInstancesOprHolder.value = params -> { |
| Assertions.assertEquals("consumerId2", params[0]); |
| assertCounter.value++; |
| return preservedLogic.apply(params); |
| }; |
| microserviceCache.refresh(); |
| Assertions.assertEquals(Integer.valueOf(2), assertCounter.value); |
| } |
| } |