private List<CallableProcedure> compile( Class<?> clazz ) throws KernelException { return new ReflectiveProcedureCompiler( new TypeMappers(), new ComponentRegistry(), new ComponentRegistry(), NullLog.getInstance(), ProcedureConfig.DEFAULT ).compileProcedure( clazz, null, true ); } }
@Test public void staticFieldsAreAllowed() throws Throwable { // Given FieldInjections injections = new FieldInjections( new ComponentRegistry() ); // When List<FieldInjections.FieldSetter> setters = injections.setters( ProcedureWithStaticFields.class ); // Then assertEquals( 0, setters.size() ); }
private ComponentRegistry registryWithUnsafeAPI() { ComponentRegistry allComponents = new ComponentRegistry(); allComponents.register( UnsafeAPI.class, ctx -> new UnsafeAPI() ); return allComponents; }
@Test public void shouldNotAllowNonPublicFieldsForInjection() throws Throwable { // Given FieldInjections injections = new FieldInjections( new ComponentRegistry() ); // Expect exception.expect( ProcedureException.class ); exception.expectMessage( "Field `someState` on `ProcedureWithPrivateMemberField` must be non-final and public." ); // When injections.setters( ProcedureWithPrivateMemberField.class ); }
@Test public void shouldNotLoadNoneWhiteListedFunction() throws Throwable { // Given Log log = spy(Log.class); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), log, new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "WrongName" ) ) ); List<CallableUserAggregationFunction> method = compile( SingleAggregationFunction.class ); verify( log ).warn( "The function 'org.neo4j.kernel.impl.proc.collectCool' is not on the whitelist and won't be loaded." ); assertThat( method.size(), equalTo( 0 ) ); }
@Test public void shouldNotLoadNoneWhiteListedFunction() throws Throwable { // Given Log log = spy(Log.class); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), log, new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "WrongName" ) ) ); List<CallableUserFunction> method = compile( SingleReadOnlyFunction.class ); verify( log ).warn( "The function 'org.neo4j.kernel.impl.proc.listCoolPeople' is not on the whitelist and won't be loaded." ); assertThat( method.size(), equalTo( 0 ) ); }
@Test public void shouldNotLoadAnyFunctionIfConfigIsEmpty() throws Throwable { // Given Log log = spy(Log.class); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), log, new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "" ) ) ); List<CallableUserAggregationFunction> method = compile( SingleAggregationFunction.class ); verify( log ).warn( "The function 'org.neo4j.kernel.impl.proc.collectCool' is not on the whitelist and won't be loaded." ); assertThat( method.size(), equalTo( 0 ) ); }
@Test public void shouldNotAllowClassesWithNonInjectedFields() throws Throwable { // Given FieldInjections injections = new FieldInjections( new ComponentRegistry() ); // Expect exception.expect( ProcedureException.class ); exception.expectMessage( "Field `someState` on `ProcedureWithNonInjectedMemberFields` " + "is not annotated as a @Context and is not static. " + "If you want to store state along with your procedure, " + "please use a static field." ); // When injections.setters( ProcedureWithNonInjectedMemberFields.class ); }
@Test public void shouldNotLoadAnyFunctionIfConfigIsEmpty() throws Throwable { // Given Log log = spy(Log.class); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), log, new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "" ) ) ); List<CallableUserFunction> method = compile( SingleReadOnlyFunction.class ); verify( log ).warn( "The function 'org.neo4j.kernel.impl.proc.listCoolPeople' is not on the whitelist and won't be loaded." ); assertThat( method.size(), equalTo( 0 ) ); }
@Test public void shouldReturnEmptySetOnNullArgument() throws Exception { // given ProcedureJarLoader jarloader = new ProcedureJarLoader( new ReflectiveProcedureCompiler( new TypeMappers(), new ComponentRegistry(), registryWithUnsafeAPI(), log, procedureConfig() ), NullLog.getInstance() ); // when ProcedureJarLoader.Callables callables = jarloader.loadProceduresFromDir( null ); // then assertEquals( 0, callables.procedures().size() + callables.functions().size() ); }
@Test public void shouldLoadWhiteListedFunction() throws Throwable { // Given procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), NullLog.getInstance(), new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "org.neo4j.kernel.impl.proc.listCoolPeople" ) ) ); CallableUserFunction method = compile( SingleReadOnlyFunction.class ).get( 0 ); // Expect Object out = method.apply( new BasicContext(), new AnyValue[0] ); assertThat(out, equalTo( ValueUtils.of( Arrays.asList("Bonnie", "Clyde") ) ) ); }
@Before public void setUp() { ComponentRegistry safeComponents = new ComponentRegistry(); ComponentRegistry allComponents = new ComponentRegistry(); safeComponents.register( MyAwesomeAPI.class, ctx -> new MyAwesomeAPI() ); allComponents.register( MyAwesomeAPI.class, ctx -> new MyAwesomeAPI() ); allComponents.register( MyUnsafeAPI.class, ctx -> new MyUnsafeAPI() ); compiler = new ReflectiveProcedureCompiler( new TypeMappers(), safeComponents, allComponents, log, ProcedureConfig.DEFAULT ); }
@Before public void setUp() { components = new ComponentRegistry(); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, components, NullLog.getInstance(), ProcedureConfig.DEFAULT ); }
@Test public void shouldLoadWhiteListedFunction() throws Throwable { // Given procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, new ComponentRegistry(), NullLog.getInstance(), new ProcedureConfig( Config.defaults( GraphDatabaseSettings.procedure_whitelist, "org.neo4j.kernel.impl.proc.collectCool" ) ) ); CallableUserAggregationFunction method = compile( SingleAggregationFunction.class ).get( 0 ); // Expect UserAggregator created = method.create( new BasicContext() ); created.update( new Object[]{"Bonnie"} ); assertThat(created.result(), equalTo( Collections.singletonList( "Bonnie" ) ) ); }
@Before public void setUp() { components = new ComponentRegistry(); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, components, NullLog.getInstance(), ProcedureConfig.DEFAULT ); }
@Before public void setUp() { components = new ComponentRegistry(); procedureCompiler = new ReflectiveProcedureCompiler( new TypeMappers(), components, components, NullLog.getInstance(), ProcedureConfig.DEFAULT ); }
@Test public void shouldLogHelpfullyWhenPluginJarIsCorrupt() throws Exception { // given URL theJar = createJarFor( ClassWithOneProcedure.class, ClassWithAnotherProcedure.class, ClassWithNoProcedureAtAll.class ); corruptJar( theJar ); AssertableLogProvider logProvider = new AssertableLogProvider( true ); ProcedureJarLoader jarloader = new ProcedureJarLoader( new ReflectiveProcedureCompiler( new TypeMappers(), new ComponentRegistry(), registryWithUnsafeAPI(), log, procedureConfig() ), logProvider.getLog( ProcedureJarLoader.class ) ); // when try { jarloader.loadProceduresFromDir( parentDir( theJar ) ); fail( "Should have logged and thrown exception." ); } catch ( ZipException expected ) { // then logProvider.assertContainsLogCallContaining( escapeJava( String.format( "Plugin jar file: %s corrupted.", new File( theJar.toURI() ).toPath() ) ) ); } }
@Test public void shouldWorkOnPathsWithSpaces() throws Exception { // given File fileWithSpacesInName = tmpdir.newFile( new Random().nextInt() + " some spaces in the filename" + ".jar" ); URL theJar = new JarBuilder().createJarFor( fileWithSpacesInName, ClassWithOneProcedure.class ); corruptJar( theJar ); AssertableLogProvider logProvider = new AssertableLogProvider( true ); ProcedureJarLoader jarloader = new ProcedureJarLoader( new ReflectiveProcedureCompiler( new TypeMappers(), new ComponentRegistry(), registryWithUnsafeAPI(), log, procedureConfig() ), logProvider.getLog( ProcedureJarLoader.class ) ); // when try { jarloader.loadProceduresFromDir( parentDir( theJar ) ); fail( "Should have logged and thrown exception." ); } catch ( ZipException expected ) { // then logProvider.assertContainsLogCallContaining( escapeJava( String.format( "Plugin jar file: %s corrupted.", fileWithSpacesInName.toPath() ) ) ); } }
@Test public void inheritanceIsAllowed() throws Throwable { // Given ComponentRegistry components = new ComponentRegistry(); components.register( int.class, ctx -> 1337 ); FieldInjections injections = new FieldInjections( components ); // When List<FieldInjections.FieldSetter> setters = injections.setters( ChildProcedure.class ); // Then ChildProcedure childProcedure = new ChildProcedure(); for ( FieldInjections.FieldSetter setter : setters ) { setter.apply( null, childProcedure ); } assertEquals( 1337, childProcedure.childField ); assertEquals( 1337, childProcedure.parentField ); }
@Test public void syntheticsAllowed() throws Throwable { // Given ComponentRegistry components = new ComponentRegistry(); components.register( int.class, ctx -> 1337 ); FieldInjections injections = new FieldInjections( components ); // When List<FieldInjections.FieldSetter> setters = injections.setters( Outer.ClassWithSyntheticField.class ); // Then Outer.ClassWithSyntheticField syntheticField = new Outer().classWithSyntheticField(); for ( FieldInjections.FieldSetter setter : setters ) { setter.apply( null, syntheticField ); } assertEquals( 1337, syntheticField.innerField ); }