Polish Observation Tests

Check all observable operations

Issue-991
This commit is contained in:
Josh Cummings
2025-01-09 12:51:12 -07:00
parent 3b2df07db7
commit cc1a15f76e
2 changed files with 489 additions and 489 deletions

View File

@@ -40,18 +40,19 @@ import javax.naming.ldap.ExtendedResponse;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.LdapName;
import com.mysema.commons.lang.Assert;
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationConvention;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.lang.NonNull;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DirContextProxy;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -73,7 +74,7 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
public ObservationContextSource(BaseLdapPathContextSource contextSource, ObservationRegistry observationRegistry) {
Assert.notNull(contextSource, "contextSource cannot be null");
Assert.notNull(observationRegistry, "observationRegistry cannot be null");
Assert.isFalse(contextSource instanceof ObservationContextSource,
Assert.isTrue(!(contextSource instanceof ObservationContextSource),
"contextSource is already wrapped in an ObservationContextSource");
this.contextSource = contextSource;
this.registry = observationRegistry;
@@ -180,6 +181,7 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
static final String OBSERVATION_NAME = "spring.ldap.dir.context.operations";
@NonNull
@Override
public KeyValues getLowCardinalityKeyValues(DirContextOperationObservationContext context) {
return KeyValues.of("urls", context.getUrls())
@@ -188,7 +190,7 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
}
@Override
public boolean supportsContext(io.micrometer.observation.Observation.Context context) {
public boolean supportsContext(@NonNull Observation.Context context) {
return context instanceof DirContextOperationObservationContext;
}
@@ -204,7 +206,31 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
}
private static class ObservationLdapContext extends ObservationDirContext implements LdapContext {
private interface DelegatingLdapContext extends LdapContext, DirContextProxy {
default LdapContext newInstance(Control[] requestControls) throws javax.naming.NamingException {
return ((LdapContext) getTargetContext()).newInstance(requestControls);
}
default Control[] getConnectControls() throws javax.naming.NamingException {
return ((LdapContext) getTargetContext()).getConnectControls();
}
default void setRequestControls(Control[] requestControls) throws javax.naming.NamingException {
((LdapContext) getTargetContext()).setRequestControls(requestControls);
}
default Control[] getRequestControls() throws javax.naming.NamingException {
return ((LdapContext) getTargetContext()).getRequestControls();
}
default Control[] getResponseControls() throws javax.naming.NamingException {
return ((LdapContext) getTargetContext()).getResponseControls();
}
}
private static class ObservationLdapContext extends ObservationDirContext implements DelegatingLdapContext {
private final LdapContext delegate;
@@ -216,50 +242,61 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
@Override
public ExtendedResponse extendedOperation(ExtendedRequest request) throws javax.naming.NamingException {
Observation observation = observation("extended.operation");
Observation observation = observation("extendedOperation");
observation.highCardinalityKeyValue("request.id", request.getID());
return observe(observation, () -> this.delegate.extendedOperation(request));
return observation.observeChecked(() -> this.delegate.extendedOperation(request));
}
@Override
public LdapContext newInstance(Control[] requestControls) throws javax.naming.NamingException {
return this.delegate.newInstance(requestControls);
}
@Override
public void reconnect(Control[] connCtls) throws javax.naming.NamingException {
public void reconnect(Control[] controls) throws javax.naming.NamingException {
Observation observation = observation("reconnect");
List<String> ids = new ArrayList<>();
for (Control control : connCtls) {
for (Control control : controls) {
ids.add(control.getID());
}
observation.highCardinalityKeyValue("control.ids", ids.toString());
observe(observation, () -> this.delegate.reconnect(connCtls));
}
@Override
public Control[] getConnectControls() throws javax.naming.NamingException {
return this.delegate.getConnectControls();
}
@Override
public void setRequestControls(Control[] requestControls) throws javax.naming.NamingException {
this.delegate.setRequestControls(requestControls);
}
@Override
public Control[] getRequestControls() throws javax.naming.NamingException {
return this.delegate.getRequestControls();
}
@Override
public Control[] getResponseControls() throws javax.naming.NamingException {
return this.delegate.getResponseControls();
observation.observeChecked(() -> this.delegate.reconnect(controls));
}
}
private static class ObservationDirContext implements DirContext, DirContextProxy {
private interface DelegatingDirContext extends DirContext, DirContextProxy {
default NameParser getNameParser(Name name) throws javax.naming.NamingException {
return getTargetContext().getNameParser(name);
}
default NameParser getNameParser(String name) throws javax.naming.NamingException {
return getTargetContext().getNameParser(name);
}
default Name composeName(Name name, Name prefix) throws javax.naming.NamingException {
return getTargetContext().composeName(name, prefix);
}
default String composeName(String name, String prefix) throws javax.naming.NamingException {
return getTargetContext().composeName(name, prefix);
}
default Object addToEnvironment(String propName, Object propVal) throws javax.naming.NamingException {
return getTargetContext().addToEnvironment(propName, propVal);
}
default Object removeFromEnvironment(String propName) throws javax.naming.NamingException {
return getTargetContext().removeFromEnvironment(propName);
}
default Hashtable<?, ?> getEnvironment() throws javax.naming.NamingException {
return getTargetContext().getEnvironment();
}
default void close() throws javax.naming.NamingException {
getTargetContext().close();
}
}
private static class ObservationDirContext extends AbstractDirContextProxy implements DelegatingDirContext {
private final ObservationRegistry registry;
@@ -267,15 +304,332 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
private final DirContextOperationObservationContext.Builder builder;
private final DirContext delegate;
ObservationDirContext(DirContextOperationObservationContext.Builder builder, DirContext delegate,
ObservationRegistry registry) {
super(delegate);
this.builder = builder;
this.delegate = delegate;
this.registry = registry;
}
@Override
public Attributes getAttributes(Name name) throws javax.naming.NamingException {
Observation observation = observation("getAttributes").highCardinalityKeyValue("name", name.toString());
return observation.observeChecked(() -> getTargetContext().getAttributes(name));
}
@Override
public Attributes getAttributes(String name) throws javax.naming.NamingException {
Observation observation = observation("getAttributes").highCardinalityKeyValue("name", name);
return observation.observeChecked(() -> getTargetContext().getAttributes(name));
}
@Override
public Attributes getAttributes(Name name, String[] attrIds) throws javax.naming.NamingException {
Observation observation = observation("getAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrIds));
return observation.observeChecked(() -> getTargetContext().getAttributes(name, attrIds));
}
@Override
public Attributes getAttributes(String name, String[] attrIds) throws javax.naming.NamingException {
Observation observation = observation("getAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrIds));
return observation.observeChecked(() -> getTargetContext().getAttributes(name, attrIds));
}
@Override
public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("modifyAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mod_op, attrs));
observation.observeChecked(() -> getTargetContext().modifyAttributes(name, mod_op, attrs));
}
@Override
public void modifyAttributes(String name, int mod_op, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("modifyAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mod_op, attrs));
observation.observeChecked(() -> getTargetContext().modifyAttributes(name, mod_op, attrs));
}
@Override
public void modifyAttributes(Name name, ModificationItem[] mods) throws javax.naming.NamingException {
Observation observation = observation("modifyAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mods));
observation.observeChecked(() -> getTargetContext().modifyAttributes(name, mods));
}
@Override
public void modifyAttributes(String name, ModificationItem[] mods) throws javax.naming.NamingException {
Observation observation = observation("modifyAttributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mods));
observation.observeChecked(() -> getTargetContext().modifyAttributes(name, mods));
}
@Override
public void bind(Name name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observation.observeChecked(() -> getTargetContext().bind(name, obj, attrs));
}
@Override
public void bind(String name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observation.observeChecked(() -> getTargetContext().bind(name, obj, attrs));
}
@Override
public void rebind(Name name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observation.observeChecked(() -> getTargetContext().rebind(name, obj, attrs));
}
@Override
public void rebind(String name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observation.observeChecked(() -> getTargetContext().rebind(name, obj, attrs));
}
@Override
public DirContext createSubcontext(Name name, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("createSubcontext").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
return observation.observeChecked(() -> getTargetContext().createSubcontext(name, attrs));
}
@Override
public DirContext createSubcontext(String name, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("createSubcontext").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
return observation.observeChecked(() -> getTargetContext().createSubcontext(name, attrs));
}
@Override
public DirContext getSchema(Name name) throws javax.naming.NamingException {
Observation observation = observation("getSchema").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().getSchema(name));
}
@Override
public DirContext getSchema(String name) throws javax.naming.NamingException {
Observation observation = observation("getSchema").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().getSchema(name));
}
@Override
public DirContext getSchemaClassDefinition(Name name) throws javax.naming.NamingException {
Observation observation = observation("getSchemaClassDefinition").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().getSchemaClassDefinition(name));
}
@Override
public DirContext getSchemaClassDefinition(String name) throws javax.naming.NamingException {
Observation observation = observation("getSchemaClassDefinition").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().getSchemaClassDefinition(name));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes,
String[] attributesToReturn) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(attributesToReturn));
return observation
.observeChecked(() -> getTargetContext().search(name, matchingAttributes, attributesToReturn));
}
@Override
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
String[] attributesToReturn) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes))
.highCardinalityKeyValue(attributeIdsReturn(attributesToReturn));
return observation
.observeChecked(() -> getTargetContext().search(name, matchingAttributes, attributesToReturn));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes));
return observation.observeChecked(() -> getTargetContext().search(name, matchingAttributes));
}
@Override
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes));
return observation.observeChecked(() -> getTargetContext().search(name, matchingAttributes));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observation.observeChecked(() -> getTargetContext().search(name, filter, cons));
}
@Override
public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observation.observeChecked(() -> getTargetContext().search(name, filter, cons));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, String filterExpr, Object[] filterArgs,
SearchControls cons) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observation.observeChecked(() -> getTargetContext().search(name, filterExpr, filterArgs, cons));
}
@Override
public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
SearchControls cons) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observation.observeChecked(() -> getTargetContext().search(name, filterExpr, filterArgs, cons));
}
@Override
public Object lookup(Name name) throws javax.naming.NamingException {
Observation observation = observation("lookup").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().lookup(name));
}
@Override
public Object lookup(String name) throws javax.naming.NamingException {
Observation observation = observation("lookup").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().lookup(name));
}
@Override
public void bind(Name name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().bind(name, obj));
}
@Override
public void bind(String name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().bind(name, obj));
}
@Override
public void rebind(Name name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().rebind(name, obj));
}
@Override
public void rebind(String name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().rebind(name, obj));
}
@Override
public void unbind(Name name) throws javax.naming.NamingException {
Observation observation = observation("unbind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().unbind(name));
}
@Override
public void unbind(String name) throws javax.naming.NamingException {
Observation observation = observation("unbind").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().unbind(name));
}
@Override
public void rename(Name oldName, Name newName) throws javax.naming.NamingException {
Observation observation = observation("rename").highCardinalityKeyValue(name("old.name", oldName))
.highCardinalityKeyValue(name("newName", newName));
observation.observeChecked(() -> getTargetContext().rename(oldName, newName));
}
@Override
public void rename(String oldName, String newName) throws javax.naming.NamingException {
Observation observation = observation("rename").highCardinalityKeyValue(name("old.name", oldName))
.highCardinalityKeyValue(name("newName", newName));
observation.observeChecked(() -> getTargetContext().rename(oldName, newName));
}
@Override
public NamingEnumeration<NameClassPair> list(Name name) throws javax.naming.NamingException {
Observation observation = observation("list").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().list(name));
}
@Override
public NamingEnumeration<NameClassPair> list(String name) throws javax.naming.NamingException {
Observation observation = observation("list").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().list(name));
}
@Override
public NamingEnumeration<Binding> listBindings(Name name) throws javax.naming.NamingException {
Observation observation = observation("listBindings").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().listBindings(name));
}
@Override
public NamingEnumeration<Binding> listBindings(String name) throws javax.naming.NamingException {
Observation observation = observation("listBindings").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().listBindings(name));
}
@Override
public void destroySubcontext(Name name) throws javax.naming.NamingException {
Observation observation = observation("destroySubcontext").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().destroySubcontext(name));
}
@Override
public void destroySubcontext(String name) throws javax.naming.NamingException {
Observation observation = observation("destroySubcontext").highCardinalityKeyValue(name(name));
observation.observeChecked(() -> getTargetContext().destroySubcontext(name));
}
@Override
public Context createSubcontext(Name name) throws javax.naming.NamingException {
Observation observation = observation("createSubcontext").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().createSubcontext(name));
}
@Override
public Context createSubcontext(String name) throws javax.naming.NamingException {
Observation observation = observation("createSubcontext").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().createSubcontext(name));
}
@Override
public Object lookupLink(Name name) throws javax.naming.NamingException {
Observation observation = observation("lookupLink").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().lookupLink(name));
}
@Override
public Object lookupLink(String name) throws javax.naming.NamingException {
Observation observation = observation("lookupLink").highCardinalityKeyValue(name(name));
return observation.observeChecked(() -> getTargetContext().lookupLink(name));
}
@Override
public String getNameInNamespace() throws javax.naming.NamingException {
Observation observation = observation("getNameInNamespace");
return observation.observeChecked(getTargetContext()::getNameInNamespace);
}
private static KeyValue name(String tagName, Name name) {
return KeyValue.of(tagName, String.valueOf(name));
}
@@ -297,12 +651,7 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
}
private static KeyValue attributeIds(Attributes attributes) {
if (attributes == null) {
return KeyValue.of("attribute.ids", Collections.emptyList().toString());
}
else {
return KeyValue.of("attribute.ids", Collections.list(attributes.getIDs()).toString());
}
return KeyValue.of("attribute.ids", Collections.list(attributes.getIDs()).toString());
}
private static KeyValue attributeIds(int mod_op, Attributes attrs) {
@@ -321,16 +670,22 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
}
private static KeyValue attributeIdsReturn(String[] attrs) {
if (attrs == null) {
return KeyValue.of("attribute.ids", "all");
}
return KeyValue.of("attribute.ids", Arrays.toString(attrs));
}
private static KeyValue attributeIdsReturn(SearchControls searchControls) {
if (searchControls == null) {
return attributeIdsReturn((String[]) null);
}
return attributeIdsReturn(searchControls.getReturningAttributes());
}
private static KeyValue searchControls(SearchControls searchControls) {
if (searchControls == null) {
return KeyValue.of("search.controls", "none");
return KeyValue.of("search.controls", "default");
}
return KeyValue.of("search.controls", Objects.toString(searchControls));
}
@@ -344,417 +699,26 @@ public final class ObservationContextSource implements BaseLdapPathContextSource
};
}
Observation observation(String operation) {
DirContextOperationObservationContext context = this.builder.operation(operation);
return Observation.createNotStarted(this.convention, () -> context, this.registry);
}
}
private abstract static class AbstractDirContextProxy implements DirContextProxy {
private final DirContext delegate;
AbstractDirContextProxy(DirContext delegate) {
this.delegate = delegate;
}
@Override
public DirContext getTargetContext() {
return this.delegate;
}
@Override
public Attributes getAttributes(Name name) throws javax.naming.NamingException {
DirContextOperationObservationContext context = this.builder.operation("get.attributes");
io.micrometer.observation.Observation observation = io.micrometer.observation.Observation
.createNotStarted(this.convention, () -> context, this.registry)
.highCardinalityKeyValue("name", name.toString());
return observe(observation, () -> this.delegate.getAttributes(name));
}
@Override
public Attributes getAttributes(String name) throws javax.naming.NamingException {
Observation observation = observation("get.attributes").highCardinalityKeyValue("name", name);
return observe(observation, () -> this.delegate.getAttributes(name));
}
Observation observation(String operation) {
DirContextOperationObservationContext context = this.builder.operation(operation);
return io.micrometer.observation.Observation.createNotStarted(this.convention, () -> context,
this.registry);
}
@Override
public Attributes getAttributes(Name name, String[] attrIds) throws javax.naming.NamingException {
Observation observation = observation("get.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrIds));
return observe(observation, () -> this.delegate.getAttributes(name, attrIds));
}
@Override
public Attributes getAttributes(String name, String[] attrIds) throws javax.naming.NamingException {
Observation observation = observation("get.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrIds));
return observe(observation, () -> this.delegate.getAttributes(name, attrIds));
}
@Override
public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("modify.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mod_op, attrs));
observe(observation, () -> this.delegate.modifyAttributes(name, mod_op, attrs));
}
@Override
public void modifyAttributes(String name, int mod_op, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("modify.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mod_op, attrs));
observe(observation, () -> this.delegate.modifyAttributes(name, mod_op, attrs));
}
@Override
public void modifyAttributes(Name name, ModificationItem[] mods) throws javax.naming.NamingException {
Observation observation = observation("modify.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mods));
observe(observation, () -> this.delegate.modifyAttributes(name, mods));
}
@Override
public void modifyAttributes(String name, ModificationItem[] mods) throws javax.naming.NamingException {
Observation observation = observation("modify.attributes").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(mods));
observe(observation, () -> this.delegate.modifyAttributes(name, mods));
}
@Override
public void bind(Name name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observe(observation, () -> this.delegate.bind(name, obj, attrs));
}
@Override
public void bind(String name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observe(observation, () -> this.delegate.bind(name, obj, attrs));
}
@Override
public void rebind(Name name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observe(observation, () -> this.delegate.rebind(name, obj, attrs));
}
@Override
public void rebind(String name, Object obj, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
observe(observation, () -> this.delegate.rebind(name, obj, attrs));
}
@Override
public DirContext createSubcontext(Name name, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("create.subcontext").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
return observe(observation, () -> this.delegate.createSubcontext(name, attrs));
}
@Override
public DirContext createSubcontext(String name, Attributes attrs) throws javax.naming.NamingException {
Observation observation = observation("create.subcontext").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(attrs));
return observe(observation, () -> this.delegate.createSubcontext(name, attrs));
}
@Override
public DirContext getSchema(Name name) throws javax.naming.NamingException {
Observation observation = observation("get.schema").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.getSchema(name));
}
@Override
public DirContext getSchema(String name) throws javax.naming.NamingException {
Observation observation = observation("get.schema").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.getSchema(name));
}
@Override
public DirContext getSchemaClassDefinition(Name name) throws javax.naming.NamingException {
Observation observation = observation("get.schema.class.definition").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.getSchemaClassDefinition(name));
}
@Override
public DirContext getSchemaClassDefinition(String name) throws javax.naming.NamingException {
Observation observation = observation("get.schema.class.definition").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.getSchemaClassDefinition(name));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes,
String[] attributesToReturn) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(attributesToReturn));
return observe(observation, () -> this.delegate.search(name, matchingAttributes, attributesToReturn));
}
@Override
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
String[] attributesToReturn) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes))
.highCardinalityKeyValue(attributeIdsReturn(attributesToReturn));
return observe(observation, () -> this.delegate.search(name, matchingAttributes, attributesToReturn));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes));
return observe(observation, () -> this.delegate.search(name, matchingAttributes));
}
@Override
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIds(matchingAttributes));
return observe(observation, () -> this.delegate.search(name, matchingAttributes));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observe(observation, () -> this.delegate.search(name, filter, cons));
}
@Override
public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observe(observation, () -> this.delegate.search(name, filter, cons));
}
@Override
public NamingEnumeration<SearchResult> search(Name name, String filterExpr, Object[] filterArgs,
SearchControls cons) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observe(observation, () -> this.delegate.search(name, filterExpr, filterArgs, cons));
}
@Override
public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
SearchControls cons) throws javax.naming.NamingException {
Observation observation = observation("search").highCardinalityKeyValue(name(name))
.highCardinalityKeyValue(attributeIdsReturn(cons))
.highCardinalityKeyValue(searchControls(cons));
return observe(observation, () -> this.delegate.search(name, filterExpr, filterArgs, cons));
}
@Override
public Object lookup(Name name) throws javax.naming.NamingException {
Observation observation = observation("lookup").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.lookup(name));
}
@Override
public Object lookup(String name) throws javax.naming.NamingException {
Observation observation = observation("lookup").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.lookup(name));
}
@Override
public void bind(Name name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.bind(name, obj));
}
@Override
public void bind(String name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("bind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.bind(name, obj));
}
@Override
public void rebind(Name name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.rebind(name, obj));
}
@Override
public void rebind(String name, Object obj) throws javax.naming.NamingException {
Observation observation = observation("rebind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.rebind(name, obj));
}
@Override
public void unbind(Name name) throws javax.naming.NamingException {
Observation observation = observation("unbind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.unbind(name));
}
@Override
public void unbind(String name) throws javax.naming.NamingException {
Observation observation = observation("unbind").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.unbind(name));
}
@Override
public void rename(Name oldName, Name newName) throws javax.naming.NamingException {
Observation observation = observation("rename").highCardinalityKeyValue(name("old.name", oldName))
.highCardinalityKeyValue(name("new.name", newName));
observe(observation, () -> this.delegate.rename(oldName, newName));
}
@Override
public void rename(String oldName, String newName) throws javax.naming.NamingException {
Observation observation = observation("rename").highCardinalityKeyValue(name("old.name", oldName))
.highCardinalityKeyValue(name("new.name", newName));
observe(observation, () -> this.delegate.rename(oldName, newName));
}
@Override
public NamingEnumeration<NameClassPair> list(Name name) throws javax.naming.NamingException {
Observation observation = observation("list").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.list(name));
}
@Override
public NamingEnumeration<NameClassPair> list(String name) throws javax.naming.NamingException {
Observation observation = observation("list").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.list(name));
}
@Override
public NamingEnumeration<Binding> listBindings(Name name) throws javax.naming.NamingException {
Observation observation = observation("list.bindings").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.listBindings(name));
}
@Override
public NamingEnumeration<Binding> listBindings(String name) throws javax.naming.NamingException {
Observation observation = observation("list.bindings").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.listBindings(name));
}
@Override
public void destroySubcontext(Name name) throws javax.naming.NamingException {
Observation observation = observation("destroy.subcontext").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.destroySubcontext(name));
}
@Override
public void destroySubcontext(String name) throws javax.naming.NamingException {
Observation observation = observation("destroy.subcontext").highCardinalityKeyValue(name(name));
observe(observation, () -> this.delegate.destroySubcontext(name));
}
@Override
public Context createSubcontext(Name name) throws javax.naming.NamingException {
Observation observation = observation("create.subcontext").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.createSubcontext(name));
}
@Override
public Context createSubcontext(String name) throws javax.naming.NamingException {
Observation observation = observation("create.subcontext").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.createSubcontext(name));
}
@Override
public Object lookupLink(Name name) throws javax.naming.NamingException {
Observation observation = observation("lookup.link").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.lookupLink(name));
}
@Override
public Object lookupLink(String name) throws javax.naming.NamingException {
Observation observation = observation("lookup.link").highCardinalityKeyValue(name(name));
return observe(observation, () -> this.delegate.lookupLink(name));
}
@Override
public NameParser getNameParser(Name name) throws javax.naming.NamingException {
return this.delegate.getNameParser(name);
}
@Override
public NameParser getNameParser(String name) throws javax.naming.NamingException {
return this.delegate.getNameParser(name);
}
@Override
public Name composeName(Name name, Name prefix) throws javax.naming.NamingException {
return this.delegate.composeName(name, prefix);
}
@Override
public String composeName(String name, String prefix) throws javax.naming.NamingException {
return this.delegate.composeName(name, prefix);
}
@Override
public Object addToEnvironment(String propName, Object propVal) throws javax.naming.NamingException {
return this.delegate.addToEnvironment(propName, propVal);
}
@Override
public Object removeFromEnvironment(String propName) throws javax.naming.NamingException {
return this.removeFromEnvironment(propName);
}
@Override
public Hashtable<?, ?> getEnvironment() throws javax.naming.NamingException {
return this.delegate.getEnvironment();
}
@Override
public void close() throws javax.naming.NamingException {
this.delegate.close();
}
@Override
public String getNameInNamespace() throws javax.naming.NamingException {
Observation observation = observation("get.name.in.namespace");
return observe(observation, () -> this.delegate.getNameInNamespace());
}
<T> T observe(Observation observation, ThrowableSupplier<T> supplier) throws javax.naming.NamingException {
observation.start();
try (io.micrometer.observation.Observation.Scope scope = observation.openScope()) {
return supplier.get();
}
catch (Throwable ex) {
observation.error(ex);
throw ex;
}
finally {
observation.stop();
}
}
void observe(Observation observation, ThrowableRunnable runnable) throws javax.naming.NamingException {
observation.start();
try (io.micrometer.observation.Observation.Scope scope = observation.openScope()) {
runnable.run();
}
catch (Throwable ex) {
observation.error(ex);
throw ex;
}
finally {
observation.stop();
}
}
interface ThrowableSupplier<T> {
T get() throws javax.naming.NamingException;
}
interface ThrowableRunnable {
void run() throws javax.naming.NamingException;
}
}
}

View File

@@ -16,18 +16,30 @@
package org.springframework.ldap.core.support;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.stream.Stream;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.ldap.ExtendedRequest;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.StartTlsRequest;
import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.platform.commons.support.ModifierSupport;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.support.LdapUtils;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.given;
@@ -40,38 +52,73 @@ public class ObservationContextSourceTests {
private final TestObservationRegistry registry = TestObservationRegistry.create();
private final ObservationContextSource contextSource = new ObservationContextSource(new TestContextSource(),
private final ObservationContextSource dir = new ObservationContextSource(new TestContextSource(), this.registry);
private final ObservationContextSource ldap = new ObservationContextSource(new TestContextSource(true),
this.registry);
@Test
void dirContextGetAttributesWhenObservingThenObserves() throws Exception {
this.contextSource.getReadOnlyContext().getAttributes("ou=user,ou=people");
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform get.attributes");
// @formatter:on
private final DirContext dirCtx = this.dir.getReadWriteContext();
private final LdapContext ldapCtx = (LdapContext) this.ldap.getReadWriteContext();
@TestFactory
Stream<DynamicTest> confirmObservabilityOfEachLdapContextMethod() {
return Arrays.stream(this.ldapCtx.getClass().getDeclaredMethods())
.filter(ModifierSupport::isPublic)
.map((method) -> DynamicTest.dynamicTest(methodSignature(method), () -> {
this.registry.clear();
Object[] args = Arrays.stream(method.getParameterTypes()).map(this::fuzzValue).toArray();
method.invoke(this.ldapCtx, args);
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform " + method.getName())
.hasBeenStarted().hasBeenStopped();
// @formatter:on
}));
}
@Test
void dirContextGetAttributesByNameWhenObservingThenObserves() throws Exception {
this.contextSource.getReadOnlyContext().getAttributes("ou=user,ou=people", new String[] { "id" });
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform get.attributes")
.hasHighCardinalityKeyValue("attribute.ids", "[id]");
// @formatter:on
@TestFactory
Stream<DynamicTest> confirmObservabilityOfEachDirContextMethod() {
return Arrays.stream(this.dirCtx.getClass().getDeclaredMethods())
.filter(ModifierSupport::isPublic)
.map((method) -> DynamicTest.dynamicTest(methodSignature(method), () -> {
this.registry.clear();
Object[] args = Arrays.stream(method.getParameterTypes()).map(this::fuzzValue).toArray();
method.invoke(this.dirCtx, args);
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform " + method.getName())
.hasBeenStarted().hasBeenStopped();
// @formatter:on
}));
}
@Test
void dirContextRenameWhenObservingThenObserves() throws Exception {
this.contextSource.getReadOnlyContext().rename("ou=user,ou=people", "ou=carrot,ou=people");
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform rename");
// @formatter:on
String methodSignature(Method method) {
return method.getName() + Arrays.toString(method.getParameterTypes());
}
Object fuzzValue(Class<?> type) {
if (type == String.class) {
return "";
}
if (type == Name.class) {
return LdapUtils.emptyLdapName();
}
if (type == int.class) {
return 1;
}
if (type == Attributes.class) {
return new BasicAttributes();
}
if (type.isArray()) {
return Array.newInstance(type.componentType(), 0);
}
if (type == ExtendedRequest.class) {
return new StartTlsRequest();
}
return null;
}
@Test
@@ -87,21 +134,10 @@ public class ObservationContextSourceTests {
// @formatter:on
}
@Test
void ldapContextWhenExtendedOperationThenObserves() throws Exception {
ObservationContextSource observing = new ObservationContextSource(new TestContextSource(true), this.registry);
((LdapContext) observing.getReadOnlyContext()).extendedOperation(new StartTlsRequest());
// @formatter:off
TestObservationRegistryAssert.assertThat(this.registry)
.hasObservationWithNameEqualTo("spring.ldap.dir.context.operations").that()
.hasContextualNameEqualTo("perform extended.operation");
// @formatter:on
}
@Test
void constructorWhenObservationContextSourceThenIllegalArgument() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> new ObservationContextSource(this.contextSource, this.registry));
.isThrownBy(() -> new ObservationContextSource(this.dir, this.registry));
}
@Test