How to run tests against Neo4j with custom unmanaged extension? - java

I have my own custom-written unmanaged extension for Neo4j database.
I want to run integration tests againt fully-functional database, with unmanaged extension available there.

Neo4j provides tool called neo4j-harness that makes it easier to write integration tests for unmanged extensions. More iformation is available here.
Blog post
1) Determine Neo4j version that is needed (used).
Maven:
<properties>
<version.neo4j>2.2.5</version.neo4j>
</properties>
2) Add dependency for neo4j-harness.
Maven:
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>${version.neo4j}</version>
<!-- If you want to use Neo4j server in sources, instead of tests, then remove this line -->
<scope>test</scope>
</dependency>
3) Be sure that you unmanaged extension sources is available in tests.
Maven:
If you write tests into same module with extension, then everything is OK.
If you write tests in seperate module (i.e. integration-tests), then make sure that extension is available there.
<dependency>
<groupId>my.company</groupId>
<artifactId>unmanaged-extension</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
4) Create Neo4jTestServer class that is responsible for database start-up and shutdown.
/**
* Spin-up Neo4j server with loaded unmanaged extension.
*/
public final class Neo4jTestServer {
public static final String EXTENSION_MOUNT_POINT = "/ext";
public static final String EXTENSION_RESOURCES = "my.company.extension.resources";
// Alternative way to get package
// public static final String EXTENSION_RESOURCES = SomeResource.class.getPackage().getName();
private static Neo4jTestServer INSTANCE = null;
public static synchronized Neo4jTestServer getInstance() {
if (INSTANCE == null) {
INSTANCE = new Neo4jTestServer();
}
return INSTANCE;
}
private final ServerControls serverControls;
private Neo4jTestServer() {
serverControls = TestServerBuilders.newInProcessBuilder()
.withExtension(EXTENSION_MOUNT_POINT, EXTENSION_RESOURCES)
// Resource can be specified directly
// .withExtension(EXTENSION_MOUNT_POINT, SomeResource.class)
.newServer();
}
public ServerControls getServerControls() {
return serverControls;
}
public void shutdown() {
serverControls.close();
}
}
Usage:
Neo4jTestServer server = Neo4jTestServer.getInstance();
// Get Neo4j server URI, with port
server.getServerControls().getHttpUri();
// Shutdown server
server.shutdown();
Notes:
SomeResource is JAX-RS resource that provides custom functionality
If you have more than 1 resource, and want to use class to specify unmanaged extension, instead of string - there is no need to specify all thoose classes. Neo4j will scan specified class package for other resources and load them automatically.
All resources should be in same package
Tip: You can create ResourcesRootPackageMarker class in same package, where all resources reside and use this class to specify package. It makes code more resilient to future code refactorings.
5) Optional. Specify JVM shutdown hook to shutdown database.
final Neo4jTestServer server = Neo4jTestServer.getInstance();
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
server.shutdown();
}
});
6) To verify that everything is working and your unmanaged extension is available - execute tests, start database and examine output generated by Neo4j server.
You should see something like this:
INFO: Scanning for root resource and provider classes in the packages:
my.company.extension.resources
Sep 14, 2015 5:25:15 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class my.company.extension.resources.SomeResource
class my.company.extension.resources.AnotherResource
EDIT: Graphaware test framework, information provided by MicTech
Alternatively, there is GraphAware Test framework provided by graphaware, that gives possibility to test any Neo4j-related code.
This module provides means of easily testing code that talks to the Neo4j database in one way or another. The target audience of this module are Java developers who write Neo4j-related code, as well as authors of GraphAware Modules and APIs.
Here you can find some posts about how framework can be used (autored by Graphaware developers).
Basically what you need to do is:
1) Create extension:
#Path("/helloworld")
public class HelloWorldUnmanagedExtension {
private final HelloWorldNodeCreator nodeCreator;
public HelloWorldUnmanagedExtension(#Context GraphDatabaseService database) {
nodeCreator = new HelloWorldNodeCreator(database);
}
#POST
#Path("/create")
public Response createHelloWorldNode() {
Node node = nodeCreator.createHelloWorldNode();
return Response.ok(String.valueOf(node.getId())).build();
}
}
2) Extend your test with WrappingServerIntegrationTest and necessary configuration.
public class HelloWorldUnmanagedExtensionApiTest extends WrappingServerIntegrationTest {
#Override
protected Map<String, String> thirdPartyJaxRsPackageMappings() {
return Collections.singletonMap("com.graphaware.example.unmanaged", "/ext");
}
#Test
public void shouldCreateAndReturnNode() {
String result = TestUtils.post(baseNeoUrl() + "/ext/helloworld/create", 200);
assertEquals("0", result);
GraphUnit.assertSameGraph(getDatabase(), "CREATE (:HelloWorld {hello:'world'})");
}
}
Here can be found more detailed instructions on how to test unmanaged extension with Graphaware test framework.
Everything should be up-and-running now and ready for testing. Good luck!

Related

Spring boot application not able to load SPI implementation

I have an SPI interface defined in a maven module A. In Module B, which is a spring-boot application, I have defined META-INF/services/<interface-named-file>.
In Module A, I am having this code.
public class NotificationResultPluginProvider {
private static NotificationResultPluginProvider notificationResultPluginProvider;
private NotificationResultPlugin notificationResultPlugin;
private NotificationResultPluginProvider() {
final ServiceLoader<NotificationResultPlugin> loader = ServiceLoader.load(NotificationResultPlugin.class);
final Iterator<NotificationResultPlugin> it = loader.iterator();
if (it.hasNext()) {
notificationResultPlugin = it.next();
}
}
public static synchronized NotificationResultPluginProvider getInstance() {
if (null == notificationResultPluginProvider) {
notificationResultPluginProvider = new NotificationResultPluginProvider();
}
return notificationResultPluginProvider;
}
public NotificationResultPlugin getNotificationResultPlugin() {
return notificationResultPlugin;
}
}
In Module B - spring boot app - I have an implementation of NotificationResultPlugin interface.
Now here is the pickle.
When I run the boot app from intellij, I see that (in below code) it.hasNext() is true and notificationResultPlugin is found. In this case my application is working as expected.
if (it.hasNext()) {
notificationResultPlugin = it.next();
}
But when I run the boot app with CLI, using a command like below (note I am deflating the jar first and then launching)
jar -xf <jar file>;
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12341 -cp 'BOOT-INF/lib/*:BOOT-INF/classes' <main/class/fqn>;
Then it.hasNext() is false and my implementation in Module B for given SPI is not found. As a result, my application is not working as expected. I am at wits end now.
Other relevant information:
My spring boot app, is not a web app. That is I am not exposing any rest end point. I am simply using spring-kafka with minimal dependencies.
What am I missing ? Any help is appreciated.
Found solution
As they say, mind works best when you are not trying.
ServiceLoader was not able to load the SPI implementation because META-INF/services directory was not in classpath while I am starting the application. Setting the class path correctly did the trick. Ergo, this is the change i needed to do.
-cp 'BOOT-INF/lib/*:BOOT-INF/classes:.'
Notice that extra dot at the end.

Group configuration in quarkus / microprofile

I want to group configuration items in Quarkus and use them as a Map. Something along the lines of the next application.properties:
greeting.names = tom,jane
greeting.tom.message = hello
greeting.tom.name = tom
greeting.jane.message = hi
greeting.jane.name = jane
And have them in the application in a Map, like this:
#ConfigProperties
public class GreetingConfig {
private String name;
private String message;
// getters / setters
}
And use them like this:
private Map<String, GreetingConfig> config;
They are now name indexed, but a List would also be fine (and is what I actually need):
greeting.1.message = hello
greeting.1.name = tom
greeting.2.message = hi
greeting.2.name = jane
Any ideas on how to realize this? I have a programmatic solution, but would prefer a solution by annotation only
I've had a similar problem these days.
So I wrote a simple Quarkus extension which helped me with the configuration.
You can use the guides from the Quarkus site: Quarkus - Writing Your Own Extension and Quarkus - Building my first extension,
but basically these are the steps taken in order to create the configuration:
Have some maven multi module project (not the project where the configuration will be consumed).
Execute a similar command form the project directory:
mvn io.quarkus:quarkus-maven-plugin:1.4.2.Final:create-extension -N \
-Dquarkus.artifactIdBase=keycloak-extension \
-Dquarkus.artifactIdPrefix=otaibe-commons-quarkus- \
-Dquarkus.nameBase="Keycloak extension"
This will create 'sub multi module' project there with the following modules: runtume and deployment.
Go to the runtime module and add and annotate your config class. It should be something similar to this class
In runtime module create a producer class which should register the configuration class as CDI bean:
#ApplicationScoped
public class OtaibeKeycloakQuarkusProducer {
private volatile OtaibeKeycloakConfig otaibeKeycloakConfig;
void initialize(OtaibeKeycloakConfig config) {
this.otaibeKeycloakConfig = config;
}
#Singleton
#Produces
public OtaibeKeycloakConfig otaibeKeycloakConfig() {
return otaibeKeycloakConfig;
}
}
Create a Recorder class which should initialize the Producer:
#Recorder
public class OtaibeKeycloakRecorder {
public void initOtaQuarkusProducer(BeanContainer container, OtaibeKeycloakConfig configuration) {
OtaibeKeycloakQuarkusProducer producer = container.instance(OtaibeKeycloakQuarkusProducer.class);
producer.initialize(configuration);
}
}
In deployment module you have a Processor class. Go there and register your Producer to be injectable as CDI bean and your Recorder to initialize it. Add the similar code:
#BuildStep
AdditionalBeanBuildItem beans() {
return AdditionalBeanBuildItem.builder().addBeanClasses(OtaibeKeycloakQuarkusProducer.class).build();
}
#BuildStep
#Record(ExecutionTime.RUNTIME_INIT)
void otaibeKeycloackConfigBuildItem(BeanContainerBuildItem beanContainer,
OtaibeKeycloakConfig otaibeKeycloakConfig,
OtaibeKeycloakRecorder recorder) {
recorder.initOtaQuarkusProducer(beanContainer.getValue(), otaibeKeycloakConfig);
}
You can find my implementation here.
Now, go to your initial project where the configuration will be consumed and add the runtime module as a dependency.
In order to ensure that the configuration is added properly execute the following maven command:
mvn quarkus:generate-config
Now, you can check the file src/main/resources/application.properties.example and verify whether your properties are added there. The property group should start with quarkus. plus the name of your #ConfigRoot annotation. In my case for example it will start with quarkus.otaibe.keycloak
That's it!
Now in Quarkus 2.9, you do it with #ConfigMapping (#ConfigProperties is deprecated).
#StaticInitSafe
#ConfigMapping
public interface GreetingConfigMapping {
Map<Integer, GreetingDetail> greeting();
}
interface GreetingDetail {
String name();
String message();
}
Try it in a #QuarkusTest; #Inject it.

Is there a way to update modular library without updating main application?

Before modular application organization, I had one main JavaFX application that load custom created multiple libraries for different options and possibilities in main app.
In old way of implementation, I just send new library to update, main application reads all libraries from folder and it works like a charm. But in a modular system, if my application wants to use new modular library that I send, it needs to update its module-info file, apropos I need to send updates for modular library and for main application.
Just imagine, it would be like, chrome need to send browser update for every new plugin that is created. As I can see, with Java modularity system you can't create modular applications.
Is there a way import new module without updating main application or some other way around?
Java has a class for that: ServiceLoader.
If we assume you have a “service provider” interface named PluginProvider, other modules can declare themselves to provide that service by putting this in their respective module-info.java descriptors:
provides com.john.myapp.PluginProvider with com.library.MyProvider;
Your application would then state that it uses that service in its own module-info:
uses com.john.myapp.PluginProvider;
And your application’s code would create a ModuleFinder that looks in the directory (or directories) where you expect those plugin modules to reside, then pass that ModuleFinder to a Configuration which can be used to create a ModuleLayer for the ServiceLoader:
public class PluginLoader {
private final ServiceLoader<PluginProvider> loader;
public PluginLoader() {
Path pluginDir = Paths.get(System.getProperty("user.home"),
".local", "share", "MyApplication", "plugins");
ModuleLayer layer = PluginProvider.class.getModule().getLayer();
layer = layer.defineModulesWithOneLoader(
layer.configuration().resolveAndBind(
ModuleFinder.of(),
ModuleFinder.of(pluginDir),
Collections.emptySet()),
PluginProvider.class.getClassLoader());
loader = ServiceLoader.load(layer, PluginProvider.class);
}
public Stream<PluginProvider> getAll() {
return loader.stream();
}
public void reload() {
loader.reload();
}
}
You might even want to watch the plugin directory for new or removed files:
try (WatchService watch = pluginDir.getFileSystem().newWatchService()) {
pluginDir.register(watch,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.OVERFLOW);
WatchKey key;
while ((key = watch.take()).isValid()) {
loader.reload();
key.reset();
}
}

How to debug Solr plugin?

I have written a search component to be used with SOLR. I want to debug it. I tried debugging the SOLR itself using remote debugging feature of eclipse but it doesn't work for plugin and shows source not found.
Then I tried including my plugin project as source project but that did not work either. The debugger doesn't stops at breakpoints for plugin.
Any help in this regard shall be greatly appreciated!
You can write a Junit test in your eclipse project using an embedded solr. This makes debugging easier. All you need to do, is to create the config files for the solr-core (solrconfig.xml, schema.xml, etc.; you could probably copy the solr core dir from your solr installation) in your test resources directory and point the CoreContainer to that directory. This core container can be used to get the configured solr core and your searcher.
JUnit and Solr-core are the dependencies needed.
Below is an example of the test-code:
/**
* This is a starting point for testing the component with embedded solr!
*/
public class SearchComponentTest
{
private static CoreContainer container;
private static SolrCore core;
private static final Logger logger = LoggerFactory.getLogger(DataImportRequestHandlerTest.class.getName());
/*
* PREPARE AND TEAR DOWN FOR TESTS
*/
#BeforeClass
public static void prepareClass() throws Exception
{
// create the coreContainer from conf dir in test resources
container = new CoreContainer(
DataImportRequestHandlerTest.class.getResource("/solrDir").getPath().substring(1));
container.load();
core = container.getCore("CORENAME");
logger.info("Solr core loaded!");
}
#AfterClass
public static void cleanUpClass()
{
core.close();
container.shutdown();
logger.info("Solr core shut down!");
}
/* TESTS TO RUN */
/**
* Test the search component here or just trigger it to debug
*/
#Test
public void testSearchComponent()
{
/* PREPARE */
SearchComponent mySearchComp = core.getSearchComponent("componentNameFromSolrConf");
/* RUN */
// do something with your search component
/* CHECK */
// check results with asserts :)
}
}

Eclipse JSP preview

Is there an Eclipse plugin or feature that allows previewing of JSP files? Ideally such a feature would be aware of Spring tags. It's a major pain to edit the JSP in Eclipse, then build and deploy to see the results.
I haven't seen any good plugin which will satisfy your requirement.
As an alternative you can put the jetty server's jar to your class path (I am using jetty-6.1.5.jar and jetty-util-6.1.5.jar) and write a class like the following.
package net.eduportal.jetty;
import javax.servlet.ServletContext;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.security.UserRealm;
import org.mortbay.jetty.webapp.WebAppContext;
public class JettyRunner {
public static final int PORT = 8080;
public static final String BASE_URL = "http://localhost:" + PORT;
private static final JettyRunner _instance = new JettyRunner();
public static JettyRunner getInstance() {
return _instance;
}
// ///////////////////////////////////////////////////////////////
// Singleton
// /////////////
private Server server = null;
private WebAppContext wac = null;
private JettyRunner() {
}
public interface WebApplicationInitializer {
public void init(WebAppContext wac);
}
public ServletContext getServletContext() {
return wac.getServletContext();
}
public void start() throws Exception {
if (server == null) {
server = new Server(PORT);
server.setStopAtShutdown(true);
wac = new WebAppContext();
wac.setContextPath("/test");
wac.setResourceBase("war");
wac.setClassLoader(this.getClass().getClassLoader());
server.addHandler(wac);
server.start();
}
}
public void stop() throws Exception {
if (server != null) {
server.stop();
server = null;
}
}
public static void main(String argv[]) throws Exception {
JettyRunner.getInstance().start();
}
}
The above code assumes there is a folder called "war" in the class path which contains the same WEB-INF/* folders. When you run the code from eclipse the server will start and you can view the jsps by accessing the location localhost:8080/test/*
See http://jetty.mortbay.org/jetty5/tut/Server.html
You shouldn't have to rebuild at all to see the results.
The latest Enterprise version of eclipse actually does hot code replacement of JSPs. I add the web project to Tomcat (or Glassfish or JBoss...) and any change I make in a JSP is reflected after I refresh my browser window. Obviously, when I change a Java file, I need to restart Tomcat, but that only takes 2 seconds at most.
MyEclipse provides this plugin:
http://www.myeclipseide.com/module-htmlpages-display-pid-11.html
As to whether it will be Spring tag aware is another matter though...
JBoss Tools (http://jboss.org/tools) has a visual page editor that supports JSP, HTML and even JSF.
If a tag is not supported you can right click it and add a template for it OR you can extend the supported tags by implementing the extension points.
Examples of users extending the set of supported tags are http://relation.to/Bloggers/HowToCreateAVisualDocBookEditorIn10Minutes and http://planetjbpm.wordpress.com/2009/02/25/xforms-editor-with-jboss-vpe-and-some-jbpm/
There's the Oracle Workshop for WebLogic 10g R3 which gives you the closest thing to WYSIWYG JSP editing. Despite the fact that it comes from Oracle/BEA, it works with many app servers, not just WebLogic. It is the best tool I know for JSPs and it's free. I don't about Spring tags, but it can be customized to give design time representation of tags. I'm not sure if they support Eclipse 3.4 though.
There's also JBoss Developer Studio which has good JSP visual tools.

Categories

Resources