package org.molgenis.data.validation.meta;
import org.molgenis.data.DataService;
import org.molgenis.data.Query;
import org.molgenis.data.RepositoryCollection;
import org.molgenis.data.meta.MetaDataService;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.meta.model.Package;
import org.molgenis.data.meta.system.SystemEntityTypeRegistry;
import org.molgenis.data.validation.MolgenisValidationException;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.molgenis.data.meta.AttributeType.STRING;
import static org.molgenis.data.meta.AttributeType.XREF;
import static org.molgenis.data.meta.model.AttributeMetadata.ATTRIBUTE_META_DATA;
import static org.molgenis.data.meta.model.AttributeMetadata.CHILDREN;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ATTRIBUTES;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ENTITY_TYPE_META_DATA;
import static org.molgenis.data.meta.model.Package.PACKAGE_SEPARATOR;
import static org.molgenis.data.system.model.RootSystemPackage.PACKAGE_SYSTEM;
public class EntityTypeValidatorTest
{
private EntityTypeValidator entityTypeValidator;
private DataService dataService;
private EntityType entityType = when(mock(EntityType.class).getName()).thenReturn("entity").getMock();
private Attribute idAttr;
private Attribute labelAttr;
private Query<EntityType> entityQ;
private Query<Attribute> attrQ;
private SystemEntityTypeRegistry systemEntityTypeRegistry;
@SuppressWarnings("unchecked")
@BeforeMethod
public void setUpBeforeMethod()
{
dataService = mock(DataService.class);
MetaDataService metaDataService = mock(MetaDataService.class);
when(dataService.getMeta()).thenReturn(metaDataService);
systemEntityTypeRegistry = mock(SystemEntityTypeRegistry.class);
entityTypeValidator = new EntityTypeValidator(dataService, systemEntityTypeRegistry);
String backendName = "backend";
RepositoryCollection repoCollection = mock(RepositoryCollection.class);
when(metaDataService.getBackend(backendName)).thenReturn(repoCollection);
// valid entity meta
entityType = when(mock(EntityType.class).getName()).thenReturn("entity").getMock();
idAttr = when(mock(Attribute.class).getName()).thenReturn("idAttr").getMock();
when(idAttr.getIdentifier()).thenReturn("#idAttr");
when(idAttr.getDataType()).thenReturn(STRING);
when(idAttr.isUnique()).thenReturn(true);
when(idAttr.isNillable()).thenReturn(false);
labelAttr = when(mock(Attribute.class).getName()).thenReturn("labelAttr").getMock();
when(labelAttr.getIdentifier()).thenReturn("#labelAttr");
when(labelAttr.getDataType()).thenReturn(STRING);
entityQ = mock(Query.class);
when(dataService.query(ENTITY_TYPE_META_DATA, EntityType.class)).thenReturn(entityQ);
Query<EntityType> entityQ0 = mock(Query.class);
Query<EntityType> entityQ1 = mock(Query.class);
when(entityQ.eq(ATTRIBUTES, idAttr)).thenReturn(entityQ0);
when(entityQ.eq(ATTRIBUTES, labelAttr)).thenReturn(entityQ1);
when(entityQ0.findOne()).thenReturn(null);
when(entityQ1.findOne()).thenReturn(null);
attrQ = mock(Query.class);
Query<Attribute> attrQ0 = mock(Query.class);
Query<Attribute> attrQ1 = mock(Query.class);
when(dataService.query(ATTRIBUTE_META_DATA, Attribute.class)).thenReturn(attrQ);
when(attrQ.eq(CHILDREN, idAttr)).thenReturn(attrQ0);
when(attrQ.eq(CHILDREN, labelAttr)).thenReturn(attrQ1);
when(attrQ0.findOne()).thenReturn(null);
when(attrQ1.findOne()).thenReturn(null);
String packageName = "package";
Package package_ = when(mock(Package.class).getName()).thenReturn(packageName).getMock();
when(entityType.getPackage()).thenReturn(package_);
String name = "name";
when(entityType.getName()).thenReturn(packageName + PACKAGE_SEPARATOR + name);
when(entityType.getSimpleName()).thenReturn(name);
when(entityType.getOwnAllAttributes()).thenReturn(newArrayList(idAttr, labelAttr));
when(entityType.getAllAttributes()).thenReturn(newArrayList(idAttr, labelAttr));
when(entityType.getOwnIdAttribute()).thenReturn(idAttr);
when(entityType.getOwnLabelAttribute()).thenReturn(labelAttr);
when(entityType.getOwnLookupAttributes()).thenReturn(singletonList(labelAttr));
when(entityType.isAbstract()).thenReturn(false);
when(entityType.getExtends()).thenReturn(null);
when(entityType.getBackend()).thenReturn(backendName);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Name \\[logout\\] is not allowed because it is a reserved keyword.")
public void testValidateNameIsReservedKeyword() throws Exception
{
when(entityType.getSimpleName()).thenReturn("logout");
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Name \\[attributeWithNameExceedingMaxSize\\] is too long: maximum length is 30 characters.")
public void testValidateNameIsTooLong() throws Exception
{
when(entityType.getSimpleName()).thenReturn("attributeWithNameExceedingMaxSize");
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Qualified entity name \\[package_name\\] not equal to entity package name \\[package\\] underscore entity name \\[invalidName\\]")
public void testValidateFullNameDoesNotMatchPackageAndSimpleName()
{
when(entityType.getSimpleName()).thenReturn("invalidName");
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Qualified entity name \\[name\\] not equal to entity name \\[invalidName\\]")
public void testValidateFullNameDoesNotMatchSimpleName()
{
when(entityType.getPackage()).thenReturn(null);
when(entityType.getName()).thenReturn("name");
when(entityType.getSimpleName()).thenReturn("invalidName");
entityTypeValidator.validate(entityType);
}
@Test
public void testValidateAttributeOwnedBySameEntity()
{
@SuppressWarnings("unchecked")
Query<EntityType> entityQ0 = mock(Query.class);
@SuppressWarnings("unchecked")
Query<EntityType> entityQ1 = mock(Query.class);
when(entityQ.eq(ATTRIBUTES, idAttr)).thenReturn(entityQ0);
when(entityQ.eq(ATTRIBUTES, labelAttr)).thenReturn(entityQ1);
when(entityQ0.findOne()).thenReturn(null);
when(entityQ1.findOne()).thenReturn(entityType); // same entity
when(dataService.query(ATTRIBUTE_META_DATA, Attribute.class)).thenReturn(attrQ);
when(attrQ.eq(CHILDREN, idAttr)).thenReturn(attrQ);
when(attrQ.findOne()).thenReturn(null);
entityTypeValidator.validate(entityType); // should not throw an exception
}
@Test
public void testValidateAttributePartOwnedBySameEntity()
{
when(entityQ.eq(ATTRIBUTES, idAttr)).thenReturn(entityQ);
when(entityQ.eq(ATTRIBUTES, labelAttr)).thenReturn(entityQ);
when(entityQ.findOne()).thenReturn(null);
@SuppressWarnings("unchecked")
Query<Attribute> attrQ0 = mock(Query.class);
@SuppressWarnings("unchecked")
Query<Attribute> attrQ1 = mock(Query.class);
when(dataService.query(ATTRIBUTE_META_DATA, Attribute.class)).thenReturn(attrQ);
when(attrQ.eq(CHILDREN, idAttr)).thenReturn(attrQ0);
when(attrQ.eq(CHILDREN, labelAttr)).thenReturn(attrQ1);
when(attrQ0.findOne()).thenReturn(null);
Attribute attrParent = when(mock(Attribute.class).getName()).thenReturn("attrParent").getMock();
when(attrQ1.findOne()).thenReturn(attrParent);
@SuppressWarnings("unchecked")
Query<EntityType> entityQ0 = mock(Query.class);
when(entityQ.eq(ATTRIBUTES, attrParent)).thenReturn(entityQ0);
when(entityQ0.findOne()).thenReturn(entityType);
entityTypeValidator.validate(entityType); // should not throw an exception
}
@Test
public void testValidateAttributeNotOwnedByExtendedEntity()
{
EntityType extendsEntityType = when(mock(EntityType.class).getName()).thenReturn("entity").getMock();
when(extendsEntityType.getAllAttributes()).thenReturn(emptyList());
when(extendsEntityType.isAbstract()).thenReturn(true);
when(entityType.getExtends()).thenReturn(extendsEntityType);
entityTypeValidator.validate(entityType); // should not throw an exception
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "An attribute with name \\[idAttr\\] already exists in entity \\[extendsEntity\\] or one of its parents")
public void testValidateAttributeOwnedByExtendedEntity()
{
EntityType extendsEntityType = when(mock(EntityType.class).getName()).thenReturn("extendsEntity").getMock();
when(extendsEntityType.getAllAttributes()).thenReturn(singletonList(idAttr));
when(extendsEntityType.isAbstract()).thenReturn(true);
when(entityType.getExtends()).thenReturn(extendsEntityType);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] ID attribute \\[idAttr\\] is not part of the entity attributes")
public void testValidateOwnIdAttributeInAttributes()
{
when(entityType.getOwnAllAttributes()).thenReturn(singletonList(labelAttr));
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] ID attribute \\[idAttr\\] type \\[XREF\\] is not allowed")
public void testValidateOwnIdAttributeTypeAllowed()
{
when(idAttr.getDataType()).thenReturn(XREF);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] ID attribute \\[idAttr\\] is not a unique attribute")
public void testValidateOwnIdAttributeUnique()
{
when(idAttr.isUnique()).thenReturn(false);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] ID attribute \\[idAttr\\] is not a non-nillable attribute")
public void testValidateOwnIdAttributeNonNillable()
{
when(idAttr.isNillable()).thenReturn(true);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] is missing required ID attribute")
public void testValidateOwnIdAttributeNullIdAttributeNull()
{
when(entityType.getOwnIdAttribute()).thenReturn(null);
when(entityType.getIdAttribute()).thenReturn(null);
entityTypeValidator.validate(entityType);
}
@Test
public void testValidateOwnIdAttributeNullIdAttributeNullAbstract()
{
when(entityType.isAbstract()).thenReturn(true);
when(entityType.getOwnIdAttribute()).thenReturn(null);
when(entityType.getIdAttribute()).thenReturn(null);
entityTypeValidator.validate(entityType); // valid
}
@Test
public void testValidateOwnIdAttributeNullIdAttributeNotNull()
{
when(entityType.getOwnIdAttribute()).thenReturn(null);
Attribute parentIdAttr = mock(Attribute.class);
when(entityType.getIdAttribute()).thenReturn(parentIdAttr);
entityTypeValidator.validate(entityType); // valid
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Label attribute \\[labelAttr\\] is not part of the entity attributes")
public void testValidateOwnLabelAttributeInAttributes()
{
when(entityType.getOwnAllAttributes()).thenReturn(singletonList(idAttr));
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Lookup attribute \\[labelAttr\\] is not part of the entity attributes")
public void testValidateOwnLookupAttributesInAttributes()
{
when(entityType.getOwnAllAttributes()).thenReturn(singletonList(idAttr));
when(entityType.getOwnLabelAttribute()).thenReturn(null);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Unknown backend \\[invalidBackend\\]")
public void testValidateBackend()
{
when(entityType.getBackend()).thenReturn("invalidBackend");
entityTypeValidator.validate(entityType);
}
@Test
public void testValidateExtendsFromAbstract()
{
EntityType extendsEntityType = mock(EntityType.class);
when(extendsEntityType.getName()).thenReturn("abstractEntity");
when(extendsEntityType.isAbstract()).thenReturn(true);
when(extendsEntityType.getAllAttributes()).thenReturn(emptyList());
when(entityType.getExtends()).thenReturn(extendsEntityType);
entityTypeValidator.validate(entityType); // valid
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "EntityType \\[concreteEntity\\] is not abstract; EntityType \\[package_name\\] can't extend it")
public void testValidateExtendsFromNonAbstract()
{
EntityType extendsEntityType = mock(EntityType.class);
when(extendsEntityType.getName()).thenReturn("concreteEntity");
when(extendsEntityType.isAbstract()).thenReturn(false);
when(extendsEntityType.getAllAttributes()).thenReturn(emptyList());
when(entityType.getExtends()).thenReturn(extendsEntityType);
entityTypeValidator.validate(entityType);
}
@Test
public void testValidateSystemPackageValid()
{
String packageName = PACKAGE_SYSTEM;
Package rootSystemPackage = mock(Package.class);
when(rootSystemPackage.getName()).thenReturn(packageName);
String entityName = "entity";
String qualifiedEntityName = packageName + '_' + entityName;
when(entityType.getName()).thenReturn(qualifiedEntityName);
when(entityType.getSimpleName()).thenReturn(entityName);
when(entityType.getPackage()).thenReturn(rootSystemPackage);
when(systemEntityTypeRegistry.hasSystemEntityType(qualifiedEntityName)).thenReturn(true);
entityTypeValidator.validate(entityType); // valid
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Adding entity \\[sys_myEntity\\] to system package \\[sys\\] is not allowed")
public void testValidateSystemPackageInvalid()
{
String packageName = PACKAGE_SYSTEM;
Package rootSystemPackage = mock(Package.class);
when(rootSystemPackage.getName()).thenReturn(packageName);
String entityName = "myEntity";
String qualifiedEntityName = packageName + '_' + entityName;
when(entityType.getName()).thenReturn(qualifiedEntityName);
when(entityType.getSimpleName()).thenReturn(entityName);
when(entityType.getPackage()).thenReturn(rootSystemPackage);
when(systemEntityTypeRegistry.hasSystemEntityType(qualifiedEntityName)).thenReturn(false);
entityTypeValidator.validate(entityType);
}
@Test(expectedExceptions = MolgenisValidationException.class, expectedExceptionsMessageRegExp = "Entity \\[package_name\\] contains multiple attributes with name \\[idAttr\\]")
public void testValidateAttributeWithDuplicateName()
{
when(entityType.getAllAttributes()).thenReturn(asList(idAttr, idAttr));
entityTypeValidator.validate(entityType);
}
}