Skip to content

Commit

Permalink
Improve properties merging testcases (#43734)
Browse files Browse the repository at this point in the history
  • Loading branch information
moarychan authored Jan 14, 2025
1 parent cf76689 commit d465082
Show file tree
Hide file tree
Showing 7 changed files with 544 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@

<!-- Checkstyle suppressions for azure.spring.cloud.autoconfigure.compatibility package -->
<suppress checks="MethodName" files="com.azure.spring.cloud.autoconfigure.implementation.compatibility.AzureSpringBootVersionVerifier.java"/>

<!-- Test class for spring-messaging-azure-servicebus module -->
<suppress checks="InnerAssignment" files="com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesComparer"/>
<suppress checks="InnerAssignment" files="com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesValueInjectHelper.java"/>
<!-- ### end: Spring related suppression -->

<!-- Suppress checks for Core Perf package. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
import com.azure.core.management.AzureEnvironment;
import com.azure.spring.messaging.servicebus.core.properties.NamespaceProperties;
import com.azure.spring.messaging.servicebus.core.properties.ProcessorProperties;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA;
import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ProcessorPropertiesParentMergerTests {
private final ProcessorPropertiesParentMerger merger = new ProcessorPropertiesParentMerger();

@Test
void childNotProvidedShouldUseParent() {
ProcessorProperties child = new ProcessorProperties();
Expand All @@ -31,14 +31,14 @@ void childNotProvidedShouldUseParent() {

ProcessorProperties result = merger.merge(child, parent);

Assertions.assertEquals("parent-connection-str", result.getConnectionString());
Assertions.assertEquals("parent-hostname", result.getProxy().getHostname());
Assertions.assertEquals(AZURE_US_GOVERNMENT, result.getProfile().getCloudType());
Assertions.assertEquals(AzureEnvironment.AZURE_US_GOVERNMENT.getActiveDirectoryEndpoint(),
assertEquals("parent-connection-str", result.getConnectionString());
assertEquals("parent-hostname", result.getProxy().getHostname());
assertEquals(AZURE_US_GOVERNMENT, result.getProfile().getCloudType());
assertEquals(AzureEnvironment.AZURE_US_GOVERNMENT.getActiveDirectoryEndpoint(),
result.getProfile().getEnvironment().getActiveDirectoryEndpoint());
Assertions.assertEquals("parent-domain", result.getDomainName());
Assertions.assertEquals(customEndpoint, result.getCustomEndpointAddress());
Assertions.assertEquals(AmqpTransportType.AMQP_WEB_SOCKETS, result.getClient().getTransportType());
assertEquals("parent-domain", result.getDomainName());
assertEquals(customEndpoint, result.getCustomEndpointAddress());
assertEquals(AmqpTransportType.AMQP_WEB_SOCKETS, result.getClient().getTransportType());
}

@Test
Expand All @@ -63,16 +63,16 @@ void childProvidedShouldUseChild() {

ProcessorProperties result = merger.merge(child, parent);

Assertions.assertEquals("child-connection-str", result.getConnectionString());
Assertions.assertEquals("child-hostname", result.getProxy().getHostname());
Assertions.assertEquals(3, result.getPrefetchCount());
Assertions.assertEquals(2, result.getMaxConcurrentCalls());
Assertions.assertEquals("child-domain", result.getDomainName());
Assertions.assertEquals("https://child.address.com:443", result.getCustomEndpointAddress());
Assertions.assertEquals(AZURE_CHINA, result.getProfile().getCloudType());
Assertions.assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryEndpoint(),
assertEquals("child-connection-str", result.getConnectionString());
assertEquals("child-hostname", result.getProxy().getHostname());
assertEquals(3, result.getPrefetchCount());
assertEquals(2, result.getMaxConcurrentCalls());
assertEquals("child-domain", result.getDomainName());
assertEquals("https://child.address.com:443", result.getCustomEndpointAddress());
assertEquals(AZURE_CHINA, result.getProfile().getCloudType());
assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryEndpoint(),
result.getProfile().getEnvironment().getActiveDirectoryEndpoint());
Assertions.assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType());
assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import com.azure.core.management.AzureEnvironment;
import com.azure.spring.messaging.servicebus.core.properties.NamespaceProperties;
import com.azure.spring.messaging.servicebus.core.properties.ProducerProperties;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA;
import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ProducerPropertiesParentMergerTests {
private final SenderPropertiesParentMerger merger = new SenderPropertiesParentMerger();
Expand All @@ -29,13 +29,13 @@ void childNotProvidedShouldUseParent() {

ProducerProperties result = merger.merge(child, parent);

Assertions.assertEquals("parent-connection-str", result.getConnectionString());
Assertions.assertEquals("parent-hostname", result.getProxy().getHostname());
Assertions.assertEquals(AZURE_US_GOVERNMENT, result.getProfile().getCloudType());
Assertions.assertEquals(AzureEnvironment.AZURE_US_GOVERNMENT.getActiveDirectoryEndpoint(),
assertEquals("parent-connection-str", result.getConnectionString());
assertEquals("parent-hostname", result.getProxy().getHostname());
assertEquals(AZURE_US_GOVERNMENT, result.getProfile().getCloudType());
assertEquals(AzureEnvironment.AZURE_US_GOVERNMENT.getActiveDirectoryEndpoint(),
result.getProfile().getEnvironment().getActiveDirectoryEndpoint());
Assertions.assertEquals("parent-domain", result.getDomainName());
Assertions.assertEquals(AmqpTransportType.AMQP_WEB_SOCKETS, result.getClient().getTransportType());
assertEquals("parent-domain", result.getDomainName());
assertEquals(AmqpTransportType.AMQP_WEB_SOCKETS, result.getClient().getTransportType());
}

@Test
Expand All @@ -57,14 +57,14 @@ void childProvidedShouldUseChild() {

ProducerProperties result = merger.merge(child, parent);

Assertions.assertEquals("child-connection-str", result.getConnectionString());
Assertions.assertEquals("child-hostname", result.getProxy().getHostname());
Assertions.assertEquals("test", result.getEntityName());
Assertions.assertEquals("child-domain", result.getDomainName());
Assertions.assertEquals(AZURE_CHINA, result.getProfile().getCloudType());
Assertions.assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryEndpoint(),
assertEquals("child-connection-str", result.getConnectionString());
assertEquals("child-hostname", result.getProxy().getHostname());
assertEquals("test", result.getEntityName());
assertEquals("child-domain", result.getDomainName());
assertEquals(AZURE_CHINA, result.getProfile().getCloudType());
assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryEndpoint(),
result.getProfile().getEnvironment().getActiveDirectoryEndpoint());
Assertions.assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType());
assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.spring.messaging.servicebus.implementation.properties.merger;

import com.azure.spring.messaging.servicebus.core.properties.NamespaceProperties;
import com.azure.spring.messaging.servicebus.core.properties.ProcessorProperties;
import com.azure.spring.messaging.servicebus.core.properties.ProducerProperties;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesComparer.isMergedPropertiesCorrect;
import static com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesValueInjectHelper.injectPseudoPropertyValues;
import static org.junit.jupiter.api.Assertions.assertTrue;

class PropertiesMergerUsingInjectedValuesTests {

@Test
void allParentPropertiesWillBeMergedBySenderMerger() {
// Arrange
ProducerProperties child = new ProducerProperties();

NamespaceProperties parent = new NamespaceProperties();
injectPseudoPropertyValues(parent, List.of("cloudType"), "FullyQualifiedNamespace");

// Action
SenderPropertiesParentMerger merger = new SenderPropertiesParentMerger();
ProducerProperties result = merger.merge(child, parent);

// Assertion
assertTrue(isMergedPropertiesCorrect(parent, child, result));
}

@Test
void allChildPropertiesWillBeMergedBySenderMerger() {
// Arrange
ProducerProperties child = new ProducerProperties();
injectPseudoPropertyValues(child, List.of("cloudType"), "FullyQualifiedNamespace");

NamespaceProperties parent = new NamespaceProperties();

// Action
SenderPropertiesParentMerger merger = new SenderPropertiesParentMerger();
ProducerProperties result = merger.merge(child, parent);

// Assertion
assertTrue(isMergedPropertiesCorrect(child, child, result));
}

@Test
void allParentPropertiesWillBeMergedByProcessorMerger() {
// Arrange
ProcessorProperties child = new ProcessorProperties();

NamespaceProperties parent = new NamespaceProperties();
injectPseudoPropertyValues(parent, List.of("cloudType"), "FullyQualifiedNamespace");

// Action
ProcessorPropertiesParentMerger merger = new ProcessorPropertiesParentMerger();
ProcessorProperties result = merger.merge(child, parent);

// Assertion
assertTrue(isMergedPropertiesCorrect(parent, child, result));
}

@Test
void allChildPropertiesWillBeMergedByProcessorMerger() {
// Arrange
ProcessorProperties child = new ProcessorProperties();
injectPseudoPropertyValues(child, List.of("cloudType"), "FullyQualifiedNamespace");

NamespaceProperties parent = new NamespaceProperties();

// Action
ProcessorPropertiesParentMerger merger = new ProcessorPropertiesParentMerger();
ProcessorProperties result = merger.merge(child, parent);

// Assertion
assertTrue(isMergedPropertiesCorrect(child, child, result));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.spring.messaging.servicebus.implementation.properties.merger.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.azure.spring.cloud.core.implementation.util.ClassUtils.isPrimitiveDefaultValue;
import static com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesUtils.BUILT_IN_MEMBER_VARIABLE_NAMES;
import static com.azure.spring.messaging.servicebus.implementation.properties.merger.util.TestPropertiesUtils.IGNORED_CLASSES;

public class TestPropertiesComparer {

public static <T, S> boolean isMergedPropertiesCorrect(T parent,
S child,
S result,
String... ignoredMemberVariableNames) {
Set<String> ignored = Arrays.stream(ignoredMemberVariableNames)
.map(String::toLowerCase)
.collect(Collectors.toSet());
AtomicInteger mismatchedCounter = new AtomicInteger();
return isMergedPropertiesCorrect(parent, child, result, ignored, mismatchedCounter, result.getClass());
}

private static <T, S> boolean isMergedPropertiesCorrect(T parent,
S child,
S result,
Set<String> ignored,
AtomicInteger counter,
Class<?> targetClass) {
if (IGNORED_CLASSES.contains(targetClass)) {
return true;
}

Arrays.stream(targetClass.getDeclaredMethods())
.filter(TestPropertiesUtils::isGetter)
.forEach(getter -> checkGetter(parent, child, result, ignored, counter, getter));
Class<?> parentClass = targetClass.getSuperclass();
if (parentClass != null) {
isMergedPropertiesCorrect(parent, child, result, ignored, counter, parentClass);
}
return counter.get() == 0;
}

private static <T, S> void checkGetter(T parent,
S child,
S result,
Set<String> ignored,
AtomicInteger counter,
Method getter) {
String varName = getVariableNameByGetter(getter);

String varNameLowerCase = varName.toLowerCase();
if (ignored.contains(varNameLowerCase)) {
return;
}

try {
Object gotValue = getter.invoke(result);
if (gotValue == null) {
return;
}

Class<?> returnType = getter.getReturnType();
if (isPrimitiveDefaultValue(returnType, gotValue)) {
System.out.println("Found the property that has a primitive default value: "
+ varName + "=" + gotValue);
counter.getAndIncrement();
return;
}

if (BUILT_IN_MEMBER_VARIABLE_NAMES.contains(varNameLowerCase)) {
Object builtInParent = findBuiltInNestedMemberVariable(varNameLowerCase, parent, parent.getClass());
Object builtInChild = findBuiltInNestedMemberVariable(varNameLowerCase, child, child.getClass());
isMergedPropertiesCorrect(builtInParent, builtInChild, gotValue, ignored, counter, gotValue.getClass());
return;
}

Boolean matched = isMatchedInOriginProperties(gotValue, getter.getName(), returnType, child, child.getClass());
if (matched == null) {
matched = isMatchedInOriginProperties(gotValue, getter.getName(), returnType, parent, parent.getClass());
if (matched == null) {
System.out.println("Found the property that doesn't exist in child and parent "
+ "properties: " + varName + "=" + gotValue);
counter.getAndIncrement();
return;
}
}
if (!matched) {
System.out.println("Found the property that mismatch in child and parent"
+ "properties: " + varName + "=" + gotValue);
counter.getAndIncrement();
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Check getter failed: " + getter.getName(), e);
}
}

private static <T> Object findBuiltInNestedMemberVariable(String memberVariableName, T target,
Class<?> targetClass) {
try {
Field builtInMemberVariable = targetClass.getDeclaredField(memberVariableName);
builtInMemberVariable.setAccessible(true);
return builtInMemberVariable.get(target);
} catch (NoSuchFieldException | IllegalAccessException e) {
Class<?> parentClass = targetClass.getSuperclass();
if (parentClass != null) {
return findBuiltInNestedMemberVariable(memberVariableName, target, parentClass);
}
}

throw new RuntimeException("Not found the built-in member variable: " + memberVariableName);
}

private static <S> Boolean isMatchedInOriginProperties(Object usedValue,
String getterMethodName,
Class<?> returnType,
S origin,
Class<?> targetClass) {
try {
Method getter = targetClass.getDeclaredMethod(getterMethodName);
Object gotValue = getter.invoke(origin);
if (gotValue == null) {
return null;
}

if (isPrimitiveDefaultValue(returnType, gotValue)) {
return null;
}

boolean matched = false;
switch (returnType.getSimpleName()) {
case "boolean", "Boolean", "Duration", "int",
"Integer", "long", "Long", "String" ->
matched = usedValue.equals(gotValue);
case "AmqpTransportType", "CloudType", "ServiceBusEntityType",
"ServiceBusReceiveMode", "SubQueue", "RetryMode" ->
matched = usedValue == gotValue;
default -> System.out.println("Not support the getter parameter type: " + returnType.getName());
}
return matched;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
Class<?> parentClass = targetClass.getSuperclass();
if (parentClass != null) {
return isMatchedInOriginProperties(usedValue, getterMethodName, returnType, origin, parentClass);
}
return null;
}
}

private static String getVariableNameByGetter(Method getter) {
String varName;
String getterName = getter.getName();
if (getterName.contains("get")) {
varName = getterName.substring("get".length());
} else {
varName = getterName.substring("is".length());
}
return varName;
}
}
Loading

0 comments on commit d465082

Please sign in to comment.