diff --git a/ddf-rpc-api/pom.xml b/ddf-rpc-api/pom.xml index 9fc2e72..c4f6412 100644 --- a/ddf-rpc-api/pom.xml +++ b/ddf-rpc-api/pom.xml @@ -202,17 +202,17 @@ INSTRUCTION COVEREDRATIO - 0.12 + 0.20 BRANCH COVEREDRATIO - 0.08 + 0.14 COMPLEXITY COVEREDRATIO - 0.12 + 0.18 diff --git a/ddf-rpc-api/src/main/java/com/connexta/ddf/catalog/direct/MetacardTypeMethods.java b/ddf-rpc-api/src/main/java/com/connexta/ddf/catalog/direct/MetacardTypeMethods.java index d407635..7ac704d 100644 --- a/ddf-rpc-api/src/main/java/com/connexta/ddf/catalog/direct/MetacardTypeMethods.java +++ b/ddf-rpc-api/src/main/java/com/connexta/ddf/catalog/direct/MetacardTypeMethods.java @@ -35,6 +35,12 @@ public class MetacardTypeMethods implements MethodSet { private static final String ISINJECTED_KEY = "isInjected"; + private static final String INDEXED_KEY = "indexed"; + + private static final String STORED_KEY = "stored"; + + private static final String TOKENIZED_KEY = "tokenized"; + private final Map methods; private final RpcFactory rpc = new RpcFactoryImpl(); @@ -106,6 +112,9 @@ public Map getMetacardTypeMap(List metacardTypeLis Map attributeProperties = new HashMap<>(); attributeProperties.put(TYPE_KEY, descriptor.getType().getAttributeFormat().name()); attributeProperties.put(MULTIVALUED_KEY, descriptor.isMultiValued()); + attributeProperties.put(INDEXED_KEY, descriptor.isIndexed()); + attributeProperties.put(STORED_KEY, descriptor.isStored()); + attributeProperties.put(TOKENIZED_KEY, descriptor.isTokenized()); attributeProperties.put(ID_KEY, descriptor.getName()); attributeProperties.put(ISINJECTED_KEY, false); attributes.put(descriptor.getName(), attributeProperties); @@ -122,6 +131,9 @@ public Map getMetacardTypeMap(List metacardTypeLis Map attributeProperties = new HashMap<>(); attributeProperties.put(TYPE_KEY, descriptor.getType().getAttributeFormat().name()); attributeProperties.put(MULTIVALUED_KEY, descriptor.isMultiValued()); + attributeProperties.put(INDEXED_KEY, descriptor.isIndexed()); + attributeProperties.put(STORED_KEY, descriptor.isStored()); + attributeProperties.put(TOKENIZED_KEY, descriptor.isTokenized()); attributeProperties.put(ID_KEY, descriptor.getName()); attributeProperties.put(ISINJECTED_KEY, true); Set types = diff --git a/ddf-rpc-api/src/test/java/com/connexta/ddf/catalog/direct/MetacardTypeMethodsTest.java b/ddf-rpc-api/src/test/java/com/connexta/ddf/catalog/direct/MetacardTypeMethodsTest.java new file mode 100644 index 0000000..7fe95c5 --- /dev/null +++ b/ddf-rpc-api/src/test/java/com/connexta/ddf/catalog/direct/MetacardTypeMethodsTest.java @@ -0,0 +1,473 @@ +package com.connexta.ddf.catalog.direct; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.connexta.jsonrpc.RpcMethod; +import com.connexta.jsonrpc.impl.ErrorImpl; +import ddf.catalog.data.AttributeDescriptor; +import ddf.catalog.data.AttributeRegistry; +import ddf.catalog.data.AttributeType.AttributeFormat; +import ddf.catalog.data.InjectableAttribute; +import ddf.catalog.data.MetacardType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class MetacardTypeMethodsTest { + + private static final String METACARD_TYPE_NAME = "testMetacardType"; + + private static final String OTHER_METACARD_TYPE_NAME = "otherMetacardType"; + + private static final String ATTRIBUTE_NAME = "testAttribute"; + + private static final String INJECTABLE_ATTR_NAME = "injectableAttr"; + + private MetacardTypeMethods metacardTypeMethods; + + @Mock private InjectableAttribute injectableAttribute; + + @Mock private AttributeRegistry attributeRegistry; + + @Mock private MetacardType metacardType; + + @Mock private MetacardType otherMetacardType; + + @Mock private AttributeDescriptor attributeDescriptor; + + @Mock private AttributeDescriptor injectableDescriptor; + + @Mock private ddf.catalog.data.AttributeType attributeType; + + @Mock private ddf.catalog.data.AttributeType injectableAttributeType; + + @BeforeEach + public void setUp() { + initMocks(this); + + when(metacardType.getName()).thenReturn(METACARD_TYPE_NAME); + when(metacardType.getAttributeDescriptors()) + .thenReturn(Collections.singleton(attributeDescriptor)); + + when(otherMetacardType.getName()).thenReturn(OTHER_METACARD_TYPE_NAME); + when(otherMetacardType.getAttributeDescriptors()).thenReturn(Collections.emptySet()); + + when(attributeDescriptor.getName()).thenReturn(ATTRIBUTE_NAME); + doReturn(attributeType).when(attributeDescriptor).getType(); + when(attributeType.getAttributeFormat()).thenReturn(AttributeFormat.STRING); + when(attributeDescriptor.isMultiValued()).thenReturn(false); + when(attributeDescriptor.isIndexed()).thenReturn(true); + when(attributeDescriptor.isStored()).thenReturn(true); + when(attributeDescriptor.isTokenized()).thenReturn(false); + + when(injectableAttribute.attribute()).thenReturn(INJECTABLE_ATTR_NAME); + when(injectableAttribute.metacardTypes()).thenReturn(Collections.emptySet()); + + when(injectableDescriptor.getName()).thenReturn(INJECTABLE_ATTR_NAME); + doReturn(injectableAttributeType).when(injectableDescriptor).getType(); + when(injectableAttributeType.getAttributeFormat()).thenReturn(AttributeFormat.STRING); + when(injectableDescriptor.isMultiValued()).thenReturn(false); + when(injectableDescriptor.isIndexed()).thenReturn(true); + when(injectableDescriptor.isStored()).thenReturn(true); + when(injectableDescriptor.isTokenized()).thenReturn(false); + + when(attributeRegistry.lookup(INJECTABLE_ATTR_NAME)) + .thenReturn(Optional.of(injectableDescriptor)); + } + + @Test + public void testGetMethodsReturnsCorrectKeys() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + + assertThat(methods, notNullValue()); + assertThat(methods.containsKey("ddf.catalog/allMetacardTypes"), is(true)); + assertThat(methods.containsKey("ddf.catalog/metacardType"), is(true)); + assertThat(methods.keySet(), hasSize(2)); + } + + @Test + public void testGetAllMetacardTypes() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod allTypesMethod = methods.get("ddf.catalog/allMetacardTypes"); + + Object result = allTypesMethod.apply(Collections.emptyMap()); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + assertThat(resultMap.containsKey("metacardTypes"), is(true)); + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + assertThat(metacardTypesResult.containsKey(METACARD_TYPE_NAME), is(true)); + } + + @Test + public void testGetAllMetacardTypesWithMultipleTypes() { + List metacardTypes = new ArrayList<>(); + metacardTypes.add(metacardType); + metacardTypes.add(otherMetacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod allTypesMethod = methods.get("ddf.catalog/allMetacardTypes"); + + Object result = allTypesMethod.apply(Collections.emptyMap()); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + assertThat(metacardTypesResult.containsKey(METACARD_TYPE_NAME), is(true)); + assertThat(metacardTypesResult.containsKey(OTHER_METACARD_TYPE_NAME), is(true)); + } + + @Test + public void testGetMetacardTypeSuccess() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod getTypeMethod = methods.get("ddf.catalog/metacardType"); + + Map params = new HashMap<>(); + params.put("metacardType", METACARD_TYPE_NAME); + + Object result = getTypeMethod.apply(params); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + assertThat(resultMap.containsKey("metacardTypes"), is(true)); + } + + @Test + public void testGetMetacardTypeNotFound() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod getTypeMethod = methods.get("ddf.catalog/metacardType"); + + Map params = new HashMap<>(); + params.put("metacardType", "nonExistentType"); + + Object result = getTypeMethod.apply(params); + + assertThat(result, instanceOf(ErrorImpl.class)); + ErrorImpl error = (ErrorImpl) result; + assertThat(error.getMessage(), is("Could not find the requested metacardType")); + } + + @Test + public void testGetMetacardTypeInvalidParamsNotString() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod getTypeMethod = methods.get("ddf.catalog/metacardType"); + + Map params = new HashMap<>(); + params.put("metacardType", 12345); + + Object result = getTypeMethod.apply(params); + + assertThat(result, instanceOf(ErrorImpl.class)); + ErrorImpl error = (ErrorImpl) result; + assertThat(error.getMessage(), is("`metacardType` must be present and a string value")); + } + + @Test + public void testGetMetacardTypeMissingParam() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Map methods = metacardTypeMethods.getMethods(); + RpcMethod getTypeMethod = methods.get("ddf.catalog/metacardType"); + + Map params = new HashMap<>(); + + Object result = getTypeMethod.apply(params); + + assertThat(result, instanceOf(ErrorImpl.class)); + } + + @Test + public void testGetMetacardTypeMapIncludesAttributeDescriptors() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + assertThat(resultMap.containsKey("metacardTypes"), is(true)); + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + assertThat(metacardTypesResult.containsKey(METACARD_TYPE_NAME), is(true)); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(METACARD_TYPE_NAME); + assertThat(attributes.containsKey(ATTRIBUTE_NAME), is(true)); + @SuppressWarnings("unchecked") + Map attributeProperties = (Map) attributes.get(ATTRIBUTE_NAME); + assertThat(attributeProperties.get("type"), is("STRING")); + assertThat(attributeProperties.get("multivalued"), is(false)); + assertThat(attributeProperties.get("indexed"), is(true)); + assertThat(attributeProperties.get("stored"), is(true)); + assertThat(attributeProperties.get("tokenized"), is(false)); + assertThat(attributeProperties.get("id"), is(ATTRIBUTE_NAME)); + assertThat(attributeProperties.get("isInjected"), is(false)); + } + + @Test + public void testInjectableAttributesAddedWhenNotInMetacardType() { + List metacardTypes = Collections.singletonList(otherMetacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + assertThat(metacardTypesResult.containsKey(OTHER_METACARD_TYPE_NAME), is(true)); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(OTHER_METACARD_TYPE_NAME); + assertThat(attributes.containsKey(INJECTABLE_ATTR_NAME), is(true)); + @SuppressWarnings("unchecked") + Map attributeProperties = + (Map) attributes.get(INJECTABLE_ATTR_NAME); + assertThat(attributeProperties.get("isInjected"), is(true)); + } + + @Test + public void testInjectableAttributesNotDuplicatedWhenAlreadyPresent() { + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(METACARD_TYPE_NAME); + assertThat(attributes.containsKey(ATTRIBUTE_NAME), is(true)); + } + + @Test + public void testInjectableAttributesForSpecificMetacardTypes() { + when(injectableAttribute.metacardTypes()).thenReturn(Collections.singleton(METACARD_TYPE_NAME)); + + List metacardTypes = new ArrayList<>(); + metacardTypes.add(metacardType); + metacardTypes.add(otherMetacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + + // METACARD_TYPE_NAME should have the injectable attribute + @SuppressWarnings("unchecked") + Map metacard1Attrs = + (Map) metacardTypesResult.get(METACARD_TYPE_NAME); + assertThat(metacard1Attrs.containsKey(INJECTABLE_ATTR_NAME), is(true)); + + // OTHER_METACARD_TYPE_NAME should NOT have the injectable attribute + @SuppressWarnings("unchecked") + Map metacard2Attrs = + (Map) metacardTypesResult.get(OTHER_METACARD_TYPE_NAME); + assertThat(metacard2Attrs.containsKey(INJECTABLE_ATTR_NAME), is(false)); + } + + @Test + public void testInjectableAttributeNotAddedWhenNotFoundInRegistry() { + when(attributeRegistry.lookup(INJECTABLE_ATTR_NAME)).thenReturn(Optional.empty()); + + List metacardTypes = Collections.singletonList(otherMetacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(OTHER_METACARD_TYPE_NAME); + assertThat(attributes.containsKey(INJECTABLE_ATTR_NAME), is(false)); + } + + @Test + public void testInjectableAttributesMergedIntoExistingMetacardType() { + when(otherMetacardType.getAttributeDescriptors()) + .thenReturn(Collections.singleton(attributeDescriptor)); + + List metacardTypes = new ArrayList<>(); + metacardTypes.add(metacardType); + metacardTypes.add(otherMetacardType); + List injectableAttributes = Collections.singletonList(injectableAttribute); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + + // otherMetacardType should have both its own attribute and the injectable one + @SuppressWarnings("unchecked") + Map otherMetacardAttrs = + (Map) metacardTypesResult.get(OTHER_METACARD_TYPE_NAME); + assertThat(otherMetacardAttrs.containsKey(ATTRIBUTE_NAME), is(true)); + assertThat(otherMetacardAttrs.containsKey(INJECTABLE_ATTR_NAME), is(true)); + } + + @Test + public void testGetMetacardTypeMapWithEmptyList() { + List metacardTypes = Collections.emptyList(); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + assertThat(resultMap.containsKey("metacardTypes"), is(true)); + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + assertThat(metacardTypesResult.isEmpty(), is(true)); + } + + @Test + public void testMultiValuedAttributeDescriptor() { + when(attributeDescriptor.isMultiValued()).thenReturn(true); + + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(METACARD_TYPE_NAME); + @SuppressWarnings("unchecked") + Map attributeProperties = (Map) attributes.get(ATTRIBUTE_NAME); + assertThat(attributeProperties.get("multivalued"), is(true)); + } + + @Test + public void testTokenizedAttributeDescriptor() { + when(attributeDescriptor.isTokenized()).thenReturn(true); + + List metacardTypes = Collections.singletonList(metacardType); + List injectableAttributes = Collections.emptyList(); + + metacardTypeMethods = + new MetacardTypeMethods(injectableAttributes, attributeRegistry, metacardTypes); + + Object result = metacardTypeMethods.getMetacardTypeMap(metacardTypes); + + assertThat(result, instanceOf(Map.class)); + @SuppressWarnings("unchecked") + Map resultMap = (Map) result; + @SuppressWarnings("unchecked") + Map metacardTypesResult = (Map) resultMap.get("metacardTypes"); + @SuppressWarnings("unchecked") + Map attributes = + (Map) metacardTypesResult.get(METACARD_TYPE_NAME); + @SuppressWarnings("unchecked") + Map attributeProperties = (Map) attributes.get(ATTRIBUTE_NAME); + assertThat(attributeProperties.get("tokenized"), is(true)); + } +}