Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a command line tool for linting ACLs #997

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions gemma-cli/src/main/java/ubic/gemma/core/apps/AclLinterCli.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package ubic.gemma.core.apps;

import gemma.gsec.acl.domain.AclObjectIdentity;
import gemma.gsec.model.Securable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ubic.gemma.core.util.AbstractCLI;
import ubic.gemma.model.expression.arrayDesign.ArrayDesign;
import ubic.gemma.model.expression.bioAssay.BioAssay;
import ubic.gemma.model.expression.biomaterial.BioMaterial;
import ubic.gemma.model.expression.experiment.*;

import javax.annotation.Nullable;
import java.util.List;

@Component
public class AclLinterCli extends AbstractCLI {

@Autowired
private SessionFactory sessionFactory;

@Override
protected void buildOptions( Options options ) {

}

@Override
protected void processOptions( CommandLine commandLine ) throws ParseException {

}

@Override
protected void doWork() throws Exception {
Session session = sessionFactory.openSession();
try {
warnEntitiesLackingObjectIdentity( session, ArrayDesign.class );
warnEntitiesLackingObjectIdentity( session, ExpressionExperiment.class );
warnEntitiesLackingObjectIdentity( session, ExpressionExperimentSubSet.class );
warnEntitiesLackingObjectIdentity( session, BioMaterial.class );
warnEntitiesLackingObjectIdentity( session, BioAssay.class );
warnEntitiesLackingObjectIdentity( session, ExperimentalDesign.class );
warnEntitiesLackingObjectIdentity( session, ExperimentalFactor.class );
warnEntitiesLackingObjectIdentity( session, FactorValue.class );

warnEntitiesWhoseParentObjectIsMissing( session, ExpressionExperimentSubSet.class, ExpressionExperiment.class );
warnEntitiesWhoseParentObjectIsMissing( session, BioAssay.class, ExpressionExperiment.class );
warnEntitiesWhoseParentObjectIsMissing( session, ExperimentalDesign.class, ExpressionExperiment.class );
warnEntitiesWhoseParentObjectIsMissing( session, ExperimentalFactor.class, ExpressionExperiment.class );
warnEntitiesWhoseParentObjectIsMissing( session, FactorValue.class, ExpressionExperiment.class );
} finally {
session.close();
}
}

private void warnEntitiesLackingObjectIdentity( Session session, Class<? extends Securable> clazz ) {
//language=HQL
//noinspection unchecked
List<? extends Securable> list = session
.createQuery( "select e from " + clazz.getName() + " e "
+ "where e.id not in ( " + "select aoi.identifier from AclObjectIdentity aoi where aoi.type = :type" + ")" )
.setParameter( "type", clazz.getName() )
.list();
for ( Securable ee : list ) {
addErrorObject( ee, String.format( "Object with ID %d lacks an ACL identity of type %s", ee.getId(), clazz.getName() ) );
}
}

private void warnEntitiesWhoseParentObjectIsMissing( Session session, Class<? extends Securable> clazz, Class<? extends Securable> parentType ) {
//noinspection unchecked
List<Object[]> list = session
.createQuery( "select e, aoi.parentObject from " + clazz.getName() + " e, AclObjectIdentity aoi "
+ "where aoi.identifier = e.id and aoi.type = :type "
+ "and aoi.parentObject is not null "
+ "and aoi.parentObject.identifier not in (select p.id from " + parentType.getName() + " p)" )
.setParameter( "type", clazz.getName() )
.list();
for ( Object[] ee : list ) {
Securable s = ( Securable ) ee[0];
AclObjectIdentity parentAoi = ( AclObjectIdentity ) ee[1];
addErrorObject( s, String.format( "Parent of object with ID %d does not exist; parent ACL identity is %s", s.getId(), parentAoi ) );
}
}

@Nullable
@Override
public String getCommandName() {
return "lintAcls";
}

@Nullable
@Override
public String getShortDesc() {
return null;
}

@Override
public GemmaCLI.CommandGroup getCommandGroup() {
return GemmaCLI.CommandGroup.SYSTEM;
}
}
36 changes: 36 additions & 0 deletions gemma-cli/src/test/java/ubic/gemma/core/apps/AclLinterCliTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ubic.gemma.core.apps;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import ubic.gemma.core.util.test.BaseDatabaseTest;
import ubic.gemma.persistence.util.TestComponent;

import static ubic.gemma.core.util.test.Assertions.assertThat;

@ContextConfiguration
public class AclLinterCliTest extends BaseDatabaseTest {

@Configuration
@TestComponent
static class AclLinterCliTestContextConfiguration extends BaseDatabaseTestContextConfiguration {

@Bean
public AclLinterCli aclLinterCli() {
return new AclLinterCli();
}
}

@Autowired
private AclLinterCli aclLinterCli;

@Test
public void test() {
assertThat( aclLinterCli )
.withArguments()
.hasCommandName( "lintAcls" )
.succeeds();
}
}
10 changes: 10 additions & 0 deletions gemma-cli/src/test/java/ubic/gemma/core/util/test/Assertions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ubic.gemma.core.util.test;

import ubic.gemma.core.util.CLI;

public class Assertions {

public static CliAssert assertThat( CLI cli ) {
return new CliAssert( cli );
}
}
30 changes: 30 additions & 0 deletions gemma-cli/src/test/java/ubic/gemma/core/util/test/CliAssert.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ubic.gemma.core.util.test;

import org.assertj.core.api.AbstractAssert;
import ubic.gemma.core.util.CLI;

/**
* AssertJ assertions for {@link CLI}.
*/
public class CliAssert extends AbstractAssert<CliAssert, CLI> {

private String[] args = {};

public CliAssert( CLI cli ) {
super( cli, CliAssert.class );
}

public CliAssert withArguments( String... args ) {
this.args = args;
return myself;
}

public CliAssert hasCommandName( String commandName ) {
objects.assertEqual( info, commandName, actual.getCommandName() );
return myself;
}

public void succeeds() {
objects.assertEqual( info, 0, actual.executeCommand( args ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public DataSourceInitializer( DataSource dataSource ) {
@Override
public void afterPropertiesSet() {
JdbcTestUtils.executeSqlScript( template, applicationContext.getResource( "/sql/init-acls.sql" ), false );
JdbcTestUtils.executeSqlScript( template, applicationContext.getResource( "/sql/init-entities.sql" ), false );
JdbcTestUtils.executeSqlScript( template, applicationContext.getResource( "/sql/init-indices.sql" ), false );
JdbcTestUtils.executeSqlScript( template, applicationContext.getResource( "/sql/h2/init-entities.sql" ), false );
JdbcTestUtils.executeSqlScript( template, applicationContext.getResource( "/sql/h2/init-indices.sql" ), false );
}
}
}