package rocks.inspectit.server.property; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.aop.SpringProxy; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.Advised; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import com.google.common.reflect.AbstractInvocationHandler; import rocks.inspectit.shared.all.cmr.property.spring.PropertyUpdate; import rocks.inspectit.shared.all.testbase.TestBase; import rocks.inspectit.shared.cs.cmr.property.configuration.SingleProperty; @SuppressWarnings("PMD") public class PropertyUpdateExecutorTest extends TestBase { private static final String PROPERTY1 = "property1"; private static final String PROPERTY2 = "property2"; @InjectMocks private PropertyUpdateExecutor propertyUpdateExecutor; @Mock private ConfigurableListableBeanFactory beanFactory; @Mock private TypeConverter typeConverter; @Mock private TargetSource targetSource; @BeforeMethod public void init() { Mockito.when(beanFactory.getTypeConverter()).thenReturn(typeConverter); } @Test @SuppressWarnings("unchecked") public void fieldOnePropertyNotMatchingType() { SingleProperty<Integer> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); Mockito.when(property.getValue()).thenReturn(Integer.valueOf(10)); Mockito.when(typeConverter.convertIfNecessary(Integer.valueOf(10), int.class)).thenReturn(10); FieldTestClass fieldTestClass = new FieldTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(fieldTestClass, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is((Object) fieldTestClass)); assertThat(fieldTestClass.update1, is(10)); assertThat(fieldTestClass.update2, is(nullValue())); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyFieldOnePropertyNotMatchingType() throws Exception { SingleProperty<Integer> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); Mockito.when(property.getValue()).thenReturn(Integer.valueOf(10)); Mockito.when(typeConverter.convertIfNecessary(Integer.valueOf(10), int.class)).thenReturn(10); FieldTestClass fieldTestClass = new FieldTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(fieldTestClass); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is(proxy)); assertThat(fieldTestClass.update1, is(10)); assertThat(fieldTestClass.update2, is(nullValue())); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void fieldOnePropertyMatchingType() { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass = new FieldTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(fieldTestClass, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject, is((Object) fieldTestClass)); assertThat(fieldTestClass.update1, is(0)); assertThat(fieldTestClass.update2, is(10L)); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyFieldOnePropertyMatchingType() throws Exception { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass = new FieldTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(fieldTestClass); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject, is(proxy)); assertThat(fieldTestClass.update1, is(0)); assertThat(fieldTestClass.update2, is(10L)); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void fieldTwoProperties() { SingleProperty<Integer> property1 = Mockito.mock(SingleProperty.class); Mockito.when(property1.getLogicalName()).thenReturn(PROPERTY1); Mockito.when(property1.getValue()).thenReturn(Integer.valueOf(10)); Mockito.when(typeConverter.convertIfNecessary(Integer.valueOf(10), int.class)).thenReturn(10); SingleProperty<Long> property2 = Mockito.mock(SingleProperty.class); Mockito.when(property2.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property2.getValue()).thenReturn(Long.valueOf(10)); List<SingleProperty<?>> list = new ArrayList<>(); list.add(property1); list.add(property2); FieldTestClass fieldTestClass = new FieldTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(fieldTestClass, "testClass"); propertyUpdateExecutor.executePropertyUpdates(list); assertThat(returnedObject, is((Object) fieldTestClass)); assertThat(fieldTestClass.update1, is(10)); assertThat(fieldTestClass.update2, is(10L)); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyFieldTwoProperties() throws Exception { SingleProperty<Integer> property1 = Mockito.mock(SingleProperty.class); Mockito.when(property1.getLogicalName()).thenReturn(PROPERTY1); Mockito.when(property1.getValue()).thenReturn(Integer.valueOf(10)); Mockito.when(typeConverter.convertIfNecessary(Integer.valueOf(10), int.class)).thenReturn(10); SingleProperty<Long> property2 = Mockito.mock(SingleProperty.class); Mockito.when(property2.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property2.getValue()).thenReturn(Long.valueOf(10)); List<SingleProperty<?>> list = new ArrayList<>(); list.add(property1); list.add(property2); FieldTestClass fieldTestClass = new FieldTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(fieldTestClass); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(list); assertThat(returnedObject, is(proxy)); assertThat(fieldTestClass.update1, is(10)); assertThat(fieldTestClass.update2, is(10L)); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void fieldTwoInstances() { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass1 = new FieldTestClass(); FieldTestClass fieldTestClass2 = new FieldTestClass(); Object returnedObject1 = propertyUpdateExecutor.postProcessAfterInitialization(fieldTestClass1, "testClass"); Object returnedObject2 = propertyUpdateExecutor.postProcessAfterInitialization(fieldTestClass2, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject1, is((Object) fieldTestClass1)); assertThat(returnedObject2, is((Object) fieldTestClass2)); assertThat(fieldTestClass1.update1, is(0)); assertThat(fieldTestClass1.update2, is(10L)); assertThat(fieldTestClass1.noUpdate, is(nullValue())); assertThat(fieldTestClass2.update1, is(0)); assertThat(fieldTestClass2.update2, is(10L)); assertThat(fieldTestClass2.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyFieldTwoInstances() throws Exception { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass1 = new FieldTestClass(); InvocationHandler handler1 = new TestInvocationHanler(); Object proxy1 = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler1); FieldTestClass fieldTestClass2 = new FieldTestClass(); InvocationHandler handler2 = new TestInvocationHanler(); Object proxy2 = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler2); Mockito.when(targetSource.getTarget()).thenReturn(fieldTestClass1).thenReturn(fieldTestClass2); Object returnedObject1 = propertyUpdateExecutor.postProcessAfterInitialization(proxy1, "testClass"); Object returnedObject2 = propertyUpdateExecutor.postProcessAfterInitialization(proxy2, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject1, is(proxy1)); assertThat(returnedObject2, is(proxy2)); assertThat(fieldTestClass1.update1, is(0)); assertThat(fieldTestClass1.update2, is(10L)); assertThat(fieldTestClass1.noUpdate, is(nullValue())); assertThat(fieldTestClass2.update1, is(0)); assertThat(fieldTestClass2.update2, is(10L)); assertThat(fieldTestClass2.noUpdate, is(nullValue())); } @Test public void methodOneProperty() { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); MethodTestClass testClassInstance = new MethodTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(testClassInstance, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is((Object) testClassInstance)); assertThat(testClassInstance.a, is(2)); } @Test public void proxyMethodOneProperty() throws Exception { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); MethodTestClass testClassInstance = new MethodTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(testClassInstance); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is(proxy)); assertThat(testClassInstance.a, is(2)); } @Test public void methodTwoProperties() { SingleProperty<?> property1 = Mockito.mock(SingleProperty.class); Mockito.when(property1.getLogicalName()).thenReturn(PROPERTY1); SingleProperty<?> property2 = Mockito.mock(SingleProperty.class); Mockito.when(property2.getLogicalName()).thenReturn(PROPERTY2); List<SingleProperty<?>> list = new ArrayList<>(); list.add(property1); list.add(property2); MethodTestClass testClassInstance = new MethodTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(testClassInstance, "testClass"); propertyUpdateExecutor.executePropertyUpdates(list); assertThat(returnedObject, is((Object) testClassInstance)); assertThat(testClassInstance.a, is(3)); } @Test public void proxyMethodTwoProperties() throws Exception { SingleProperty<?> property1 = Mockito.mock(SingleProperty.class); Mockito.when(property1.getLogicalName()).thenReturn(PROPERTY1); SingleProperty<?> property2 = Mockito.mock(SingleProperty.class); Mockito.when(property2.getLogicalName()).thenReturn(PROPERTY2); List<SingleProperty<?>> list = new ArrayList<>(); list.add(property1); list.add(property2); MethodTestClass testClassInstance = new MethodTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(testClassInstance); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(list); assertThat(returnedObject, is(proxy)); assertThat(testClassInstance.a, is(3)); } @Test public void methodNoProperties() { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn("someOtherProperty"); MethodTestClass testClassInstance = new MethodTestClass(); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(testClassInstance, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is((Object) testClassInstance)); assertThat(testClassInstance.a, is(0)); } @Test public void proxyMethodNoProperties() throws Exception { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn("someOtherProperty"); MethodTestClass testClassInstance = new MethodTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(testClassInstance); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is(proxy)); assertThat(testClassInstance.a, is(0)); } @Test public void methodTwoTestInstances() throws Exception { SingleProperty<?> property1 = Mockito.mock(SingleProperty.class); Mockito.when(property1.getLogicalName()).thenReturn(PROPERTY1); SingleProperty<?> property2 = Mockito.mock(SingleProperty.class); Mockito.when(property2.getLogicalName()).thenReturn(PROPERTY2); List<SingleProperty<?>> list = new ArrayList<>(); list.add(property1); list.add(property2); MethodTestClass testClassInstance1 = new MethodTestClass(); InvocationHandler handler1 = new TestInvocationHanler(); Object proxy1 = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler1); MethodTestClass testClassInstance2 = new MethodTestClass(); InvocationHandler handler2 = new TestInvocationHanler(); Object proxy2 = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler2); Mockito.when(targetSource.getTarget()).thenReturn(testClassInstance1).thenReturn(testClassInstance2); Object returnedObject1 = propertyUpdateExecutor.postProcessAfterInitialization(proxy1, "testClass"); Object returnedObject2 = propertyUpdateExecutor.postProcessAfterInitialization(proxy2, "testClass2"); propertyUpdateExecutor.executePropertyUpdates(list); assertThat(returnedObject1, is(proxy1)); assertThat(returnedObject2, is(proxy2)); assertThat(testClassInstance1.a, is(3)); assertThat(testClassInstance2.a, is(3)); } @Test @SuppressWarnings("unchecked") public void proxyFieldException() throws Exception { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass = new FieldTestClass(); Mockito.when(targetSource.getTarget()).thenThrow(RuntimeException.class); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject, is(proxy)); assertThat(fieldTestClass.update1, is(0)); assertThat(fieldTestClass.update2, is(nullValue())); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyFieldTargetNull() throws Exception { SingleProperty<Long> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY2); Mockito.when(property.getValue()).thenReturn(Long.valueOf(10)); FieldTestClass fieldTestClass = new FieldTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(null); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); Mockito.verifyZeroInteractions(typeConverter); assertThat(returnedObject, is(proxy)); assertThat(fieldTestClass.update1, is(0)); assertThat(fieldTestClass.update2, is(nullValue())); assertThat(fieldTestClass.noUpdate, is(nullValue())); } @Test @SuppressWarnings("unchecked") public void proxyMethodException() throws Exception { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); MethodTestClass testClassInstance = new MethodTestClass(); Mockito.when(targetSource.getTarget()).thenThrow(RuntimeException.class); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is(proxy)); assertThat(testClassInstance.a, is(0)); } @Test @SuppressWarnings("unchecked") public void proxyMethodTargetNull() throws Exception { SingleProperty<?> property = Mockito.mock(SingleProperty.class); Mockito.when(property.getLogicalName()).thenReturn(PROPERTY1); MethodTestClass testClassInstance = new MethodTestClass(); Mockito.when(targetSource.getTarget()).thenReturn(null); InvocationHandler handler = new TestInvocationHanler(); Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { SpringProxy.class, Advised.class }, handler); Object returnedObject = propertyUpdateExecutor.postProcessAfterInitialization(proxy, "testClass"); propertyUpdateExecutor.executePropertyUpdates(Collections.<SingleProperty<?>> singletonList(property)); assertThat(returnedObject, is(proxy)); assertThat(testClassInstance.a, is(0)); } public static final class MethodTestClass { public int a; @PropertyUpdate(properties = { PROPERTY1 }) public void property1() { a++; } @PropertyUpdate(properties = { PROPERTY2 }) public void property2() { a++; } @PropertyUpdate(properties = { PROPERTY1, PROPERTY2 }) public void property1And2() { a++; } @PropertyUpdate public void noPropertiesDefined() { a++; } } public static final class FieldTestClass { @Value("${" + PROPERTY1 + "}") public int update1; @Value("${" + PROPERTY2 + "}") public Long update2; public String noUpdate; } private final class TestInvocationHanler extends AbstractInvocationHandler { /** * {@inheritDoc} */ @Override protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { if ("getTargetSource".equals(method.getName())) { return targetSource; } return null; } } }