Skip to content

Commit

Permalink
Add a CLI to lint ACls
Browse files Browse the repository at this point in the history
Relocate H2 init SQL scripts since it's not possible to refer to them
unambiguously in gemma-cli.
  • Loading branch information
arteymix committed Jan 23, 2024
1 parent cc328ea commit 5d8d37f
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 2 deletions.
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 );
}
}
}

0 comments on commit 5d8d37f

Please sign in to comment.