Skip to content

Commit

Permalink
Merge pull request #17 from Kurok1/add_feign_tests
Browse files Browse the repository at this point in the history
add tests
  • Loading branch information
mercyblitz authored Jan 13, 2025
2 parents 7b98c27 + f6b776c commit 599b328
Show file tree
Hide file tree
Showing 14 changed files with 279 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import io.microsphere.spring.cloud.openfeign.autorefresh.FeignClientConfigurationChangedListener;
import io.microsphere.spring.cloud.openfeign.autorefresh.FeignComponentRegistry;
import io.microsphere.spring.cloud.openfeign.components.NoOpRequestInterceptor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration;
import org.springframework.cloud.openfeign.FeignBuilderCustomizer;
import org.springframework.cloud.openfeign.FeignClientProperties;
import org.springframework.context.annotation.Bean;

Expand All @@ -15,6 +17,12 @@
@AutoConfigureAfter(ConfigurationPropertiesRebinderAutoConfiguration.class)
public class FeignClientAutoRefreshConfiguration {


@Bean
public FeignBuilderCustomizer addDefaultRequestInterceptorCustomizer() {
return builder -> {builder.requestInterceptor(NoOpRequestInterceptor.INSTANCE);};
}

@Bean
public FeignClientConfigurationChangedListener feignClientConfigurationChangedListener(FeignComponentRegistry registry) {
return new FeignClientConfigurationChangedListener(registry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,11 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw

private void injectAutoRefreshCapability(FeignClientSpecification defaultSpecification) {
Class<?>[] originConfigurationClasses = defaultSpecification.getConfiguration();
if (originConfigurationClasses != null) {
int length = originConfigurationClasses.length;
Class<?>[] replacedConfigurationClasses = new Class<?>[originConfigurationClasses.length + 1];
//copy origin and inject AutoRefreshCapability
System.arraycopy(originConfigurationClasses, 0, replacedConfigurationClasses, 0, length);
replacedConfigurationClasses[length] = AUTO_REFRESH_CAPABILITY;
defaultSpecification.setConfiguration(replacedConfigurationClasses);
} else {
defaultSpecification.setConfiguration(new Class<?>[]{AUTO_REFRESH_CAPABILITY});
}
int length = originConfigurationClasses.length;
Class<?>[] replacedConfigurationClasses = new Class<?>[originConfigurationClasses.length + 1];
//copy origin and inject AutoRefreshCapability
System.arraycopy(originConfigurationClasses, 0, replacedConfigurationClasses, 0, length);
replacedConfigurationClasses[length] = AUTO_REFRESH_CAPABILITY;
defaultSpecification.setConfiguration(replacedConfigurationClasses);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.microsphere.spring.cloud.openfeign.components;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.openfeign.FeignClientProperties;
Expand All @@ -15,12 +17,14 @@
*/
public abstract class DecoratedFeignComponent<T> implements Refreshable {

private final Logger log = LoggerFactory.getLogger(getClass());

private final FeignContext feignContext;
private final String contextId;

private final FeignClientProperties clientProperties;


protected volatile T delegate;

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Expand All @@ -38,6 +42,7 @@ public DecoratedFeignComponent(String contextId, FeignContext feignContext, Feig
public T delegate() {
readLock.lock();
if (delegate == null) {
log.trace("the component {} - Creating delegate instance for contextId: {}", componentType().getSimpleName(), contextId);
readLock.unlock();
return loadInstance();
}
Expand All @@ -58,6 +63,7 @@ public String contextId() {

public void refresh() {
writeLock.lock();
log.debug("the component {} - Refreshing delegate instance for contextId: {}", componentType().getSimpleName(), contextId);
this.delegate = null;
writeLock.unlock();
}
Expand All @@ -79,10 +85,12 @@ protected T loadInstance() {
try {
T component = getFeignContext().getInstance(contextId, componentType);
if (component == null)
return BeanUtils.instantiateClass(componentType);
component = BeanUtils.instantiateClass(componentType);
this.delegate = component;
return component;
} catch (Exception e) {
return BeanUtils.instantiateClass(componentType);
} catch (Throwable ex) {
this.delegate = BeanUtils.instantiateClass(componentType);
return delegate;
} finally {
writeLock.unlock();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 0.0.1
*/
@FeignClient(contextId = "aaa", name = "aaa")
@FeignClient(contextId = "my-client", name = "my-client")
public interface BaseClient {

@GetMapping("echo")
public String echo(@RequestBody String value);
public String echo(@RequestBody String value, @RequestParam("version") String version);

}
Original file line number Diff line number Diff line change
@@ -1,39 +1,92 @@
package io.microsphere.spring.cloud.openfeign;

import io.microsphere.spring.cloud.openfeign.autoconfigure.EnableFeignAutoRefresh;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.test.context.TestPropertySource;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 0.0.1
*/
@SpringBootTest(classes = {
BaseTest.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true",
"feign.client.config.default.encoder=io.microsphere.spring.cloud.openfeign.encoder.AEncoder",
"feign.client.config.default.request-interceptors[0]=io.microsphere.spring.cloud.openfeign.requestInterceptor.ARequestInterceptor",
"feign.client.config.default.default-request-headers.app=my-app",
"feign.client.config.default.default-query-parameters.sign=my-sign",
})
@EnableAutoConfiguration
@ComponentScan(basePackages = "io.microsphere.spring.cloud.openfeign")
@TestPropertySource(
properties = {
"feign.client.config.default.encoder=io.microsphere.spring.cloud.openfeign.encoder.AEncoder",
"feign.client.config.default.request-interceptors[0]=io.microsphere.spring.cloud.openfeign.requestInterceptor.ARequestInterceptor"
}
)
@EnableFeignClients(clients = BaseClient.class)
@EnableFeignAutoRefresh
@AutoConfigureAfter(ConfigurationPropertiesRebinderAutoConfiguration.class)
public class BaseTest {
public abstract class BaseTest<T> {

private static final Logger log = LoggerFactory.getLogger(BaseTest.class);
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private Environment environment;
@Autowired
private BaseClient client;

protected abstract String afterTestComponentConfigKey();
protected abstract Class<? extends T> afterTestComponent();

public void replaceConfig() {
final String key = afterTestComponentConfigKey();
Set<String> keys = Collections.singleton(key);
final Class<?> className = afterTestComponent();
MutablePropertySources propertySources = ((ConfigurableEnvironment)this.environment).getPropertySources();
Map<String, Object> map = new HashMap<>();
log.trace("replacing config key {} with value {}", key, className.getName());
map.put(key, className);
propertySources.addFirst(new MapPropertySource("after", map));

EnvironmentChangeEvent event = new EnvironmentChangeEvent(keys);

triggerRefreshEvent();

this.publisher.publishEvent(event);
}

@Test
public void testInternal() {
try {
this.client.echo("hello", "1.0");

} catch (Exception ignored) {

}
replaceConfig();
try {
this.client.echo("world", "1.0");
} catch (Exception ignored) {

}


}

protected void triggerRefreshEvent() {
this.publisher.publishEvent(new RefreshEvent(new Object(), new Object(), "test"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,23 @@
package io.microsphere.spring.cloud.openfeign.encoder;

import io.microsphere.spring.cloud.openfeign.BaseClient;
import feign.codec.Encoder;
import io.microsphere.spring.cloud.openfeign.BaseTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.test.context.SpringBootTest;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 0.0.1
*/
public class EncoderChangedTest extends BaseTest {

@Autowired
private Environment environment;
@Autowired
private ApplicationEventPublisher eventPublisher;

@Autowired
private BaseClient baseClient;

@Test
public void testEncoderChange() {
try {
baseClient.echo("aaa");

} catch (Exception ignored) {
}
applyEnvironmentChange();
try {
baseClient.echo("bbb");
} catch (Exception ignored) {
@SpringBootTest(classes = EncoderChangedTest.class)
public class EncoderChangedTest extends BaseTest<Encoder> {

}
@Override
protected String afterTestComponentConfigKey() {
return "feign.client.config.my-client.encoder";
}

private void applyEnvironmentChange() {
Set<String> keys = Collections.singleton("feign.client.config.aaa.encoder");
MutablePropertySources propertySources = ((ConfigurableEnvironment)this.environment).getPropertySources();
Map<String, Object> map = new HashMap<>();
System.out.println("替换encoder: BEncoder");
map.put("feign.client.config.aaa.encoder", BEncoder.class);
propertySources.addFirst(new MapPropertySource("addition", map));

EnvironmentChangeEvent event = new EnvironmentChangeEvent(keys);

triggerRefreshEvent();

this.eventPublisher.publishEvent(event);
@Override
protected Class<? extends Encoder> afterTestComponent() {
return BEncoder.class;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.microsphere.spring.cloud.openfeign.errordecoder;

import feign.Response;
import feign.codec.ErrorDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 1.0
*/
public class AErrorDecoder implements ErrorDecoder {

private static final Logger log = LoggerFactory.getLogger(AErrorDecoder.class);

@Override
public Exception decode(String methodKey, Response response) {
log.trace("Error decoding {}", methodKey);
return new IllegalArgumentException("");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.microsphere.spring.cloud.openfeign.errordecoder;

import feign.codec.ErrorDecoder;
import io.microsphere.spring.cloud.openfeign.BaseTest;
import org.springframework.boot.test.context.SpringBootTest;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 1.0
*/
@SpringBootTest(classes = ErrorDecoderChangedTest.class)
public class ErrorDecoderChangedTest extends BaseTest<ErrorDecoder> {

@Override
protected String afterTestComponentConfigKey() {
return "feign.client.config.my-client.error-decoder";
}

@Override
protected Class<? extends ErrorDecoder> afterTestComponent() {
return AErrorDecoder.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.microsphere.spring.cloud.openfeign.querymapencoder;

import feign.QueryMapEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 1.0
*/
public class AQueryMapEncoder implements QueryMapEncoder {


private static final Logger log = LoggerFactory.getLogger(AQueryMapEncoder.class);

@Override
public Map<String, Object> encode(Object object) {
log.trace("AQueryMapEncoder.encode({})", object);
return new HashMap<>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.microsphere.spring.cloud.openfeign.querymapencoder;

import feign.QueryMapEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
* @author <a href="mailto:[email protected]">韩超</a>
* @since 1.0
*/
public class BQueryMapEncoder implements QueryMapEncoder {


private static final Logger log = LoggerFactory.getLogger(BQueryMapEncoder.class);

@Override
public Map<String, Object> encode(Object object) {
log.trace("AQueryMapEncoder.encode({})", object);
return new HashMap<>();
}
}
Loading

0 comments on commit 599b328

Please sign in to comment.