diff --git a/neo4j-plugins/subgraph-isomorphism/pom.xml b/neo4j-plugins/subgraph-isomorphism/pom.xml
index ba5b950..4a46293 100644
--- a/neo4j-plugins/subgraph-isomorphism/pom.xml
+++ b/neo4j-plugins/subgraph-isomorphism/pom.xml
@@ -15,6 +15,7 @@
3.2.0
1.3.0
+ UTF-8
@@ -40,6 +41,13 @@
test
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
+
org.neo4j.driver
diff --git a/neo4j-plugins/subgraph-isomorphism/src/test/java/edu/msstate/dasi/csb/neo4j/SubgraphIsomorphismTest.java b/neo4j-plugins/subgraph-isomorphism/src/test/java/edu/msstate/dasi/csb/neo4j/SubgraphIsomorphismTest.java
new file mode 100644
index 0000000..ad540b3
--- /dev/null
+++ b/neo4j-plugins/subgraph-isomorphism/src/test/java/edu/msstate/dasi/csb/neo4j/SubgraphIsomorphismTest.java
@@ -0,0 +1,310 @@
+package edu.msstate.dasi.csb.neo4j;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.neo4j.driver.v1.*;
+import org.neo4j.harness.junit.Neo4jRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test for the subgraph isomorphism Java plugin
+ */
+public class SubgraphIsomorphismTest {
+
+ // This rule starts a Neo4j instance
+ @Rule
+ public Neo4jRule neo4j = new Neo4jRule()
+
+ // This is the procedure we want to test
+ .withProcedure(SubgraphIsomorphism.class);
+
+ // This is the 1/3 tests for the subgraph isomorphism java plugin
+ @Test
+ public void test1() throws Throwable {
+ // This is in a try-block, to make sure we close the driver after the test
+ try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build()
+ .withoutEncryption().toConfig())) {
+ // create a session for the test
+ Session session = driver.session();
+
+ //create the first pattern graph for the test, it is also the target graph
+ session.run("CREATE (p:Pattern1 {number:'1'})");
+
+ session.run("CREATE (p:Pattern1 {number:'2'})");
+
+ session.run("CREATE (p:Pattern1 {number:'3'})");
+
+ session.run("CREATE (p:Pattern1 {number:'4'})");
+
+ session.run("CREATE (p:Pattern1 {number:'5'})");
+
+ session.run("MATCH (a:Pattern1),(b:Pattern1) WHERE a.number='1' AND b.number='5' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern1),(b:Pattern1) WHERE a.number='2' AND b.number='5' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern1),(b:Pattern1) WHERE a.number='3' AND b.number='5' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern1),(b:Pattern1) WHERE a.number='4' AND b.number='5' CREATE (a)-[r:connected]->(b)");
+
+
+ //execute the plugin as a Cypher query and fetch the result
+ StatementResult result = session.run("CALL csb.subgraphIsomorphism('Pattern1','Pattern1')");
+
+ List resultList = result.list();//convert the result record stream to list
+
+ assertThat(resultList.size(), is(120)); //the result has correct number of subgraphs
+
+ assertThat(result.keys().size(), is(3));//the result has correct number of keys
+
+ assertThat(result.keys(), contains("subgraphIndex", "patternNode", "targetNode"));//the result has correct ordered keys
+
+ //split the actual result record into columns
+ List actualColumn1 = new ArrayList<>();
+
+ List actualColumn2 = new ArrayList<>();
+
+ List actualColumn3 = new ArrayList<>();
+
+ // fetch each column of the result record
+ resultList.forEach(record -> {
+
+ actualColumn1.add(record.get(0).asLong());
+
+ actualColumn2.add(record.get(1).toString());
+
+ actualColumn3.add(record.get(2).toString());
+
+ });
+
+ //construct the expected result columns
+ List expectedColumn1 = new ArrayList<>();
+
+ List expectedColumn2 = new ArrayList<>();
+
+ List expectedColumn3 = new ArrayList<>(Arrays.asList(
+ "node<0>", "node<1>", "node<2>", "node<3>", "node<4>",
+ "node<0>", "node<1>", "node<3>", "node<2>", "node<4>",
+ "node<0>", "node<2>", "node<1>", "node<3>", "node<4>",
+ "node<0>", "node<2>", "node<3>", "node<1>", "node<4>",
+ "node<0>", "node<3>", "node<1>", "node<2>", "node<4>",
+ "node<0>", "node<3>", "node<2>", "node<1>", "node<4>",
+ "node<1>", "node<0>", "node<2>", "node<3>", "node<4>",
+ "node<1>", "node<0>", "node<3>", "node<2>", "node<4>",
+ "node<1>", "node<2>", "node<0>", "node<3>", "node<4>",
+ "node<1>", "node<2>", "node<3>", "node<0>", "node<4>",
+ "node<1>", "node<3>", "node<0>", "node<2>", "node<4>",
+ "node<1>", "node<3>", "node<2>", "node<0>", "node<4>",
+ "node<2>", "node<0>", "node<1>", "node<3>", "node<4>",
+ "node<2>", "node<0>", "node<3>", "node<1>", "node<4>",
+ "node<2>", "node<1>", "node<0>", "node<3>", "node<4>",
+ "node<2>", "node<1>", "node<3>", "node<0>", "node<4>",
+ "node<2>", "node<3>", "node<0>", "node<1>", "node<4>",
+ "node<2>", "node<3>", "node<1>", "node<0>", "node<4>",
+ "node<3>", "node<0>", "node<1>", "node<2>", "node<4>",
+ "node<3>", "node<0>", "node<2>", "node<1>", "node<4>",
+ "node<3>", "node<1>", "node<0>", "node<2>", "node<4>",
+ "node<3>", "node<1>", "node<2>", "node<0>", "node<4>",
+ "node<3>", "node<2>", "node<0>", "node<1>", "node<4>",
+ "node<3>", "node<2>", "node<1>", "node<0>", "node<4>"));
+
+ for (Long i = 0L; i < 24; i++) {
+
+ for (int j = 0; j < 5; j++)
+ expectedColumn1.add(i);
+
+ expectedColumn2.addAll(Arrays.asList("node<3>", "node<0>", "node<1>", "node<2>", "node<4>"));
+
+ }
+
+
+ //check the actual result
+ assertThat(actualColumn1, equalTo(expectedColumn1));
+
+ assertThat(actualColumn2, equalTo(expectedColumn2));
+
+ assertThat(actualColumn3, equalTo(expectedColumn3));
+
+ session.close();
+
+ driver.close();
+ }
+ }
+
+ // This is the 2/3 tests
+ @Test
+ public void test2() throws Throwable {
+ try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build()
+ .withoutEncryption().toConfig())) {
+
+ Session session = driver.session();
+
+ //create the second pattern graph
+ session.run("CREATE (p:Pattern2 {number:'1'})");
+
+ session.run("CREATE (p:Pattern2 {number:'2'})");
+
+ session.run("CREATE (p:Pattern2 {number:'3'})");
+
+ session.run("MATCH (a:Pattern2),(b:Pattern2) WHERE a.number='1' AND b.number='2' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern2),(b:Pattern2) WHERE a.number='1' AND b.number='3' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern2),(b:Pattern2) WHERE a.number='2' AND b.number='3' CREATE (a)-[r:connected]->(b)");
+
+ //create the second target graph
+ session.run("CREATE (p:Target2 {number:'4'})");
+
+ session.run("CREATE (p:Target2 {number:'5'})");
+
+ session.run("CREATE (p:Target2 {number:'6'})");
+
+ session.run("CREATE (p:Target2 {number:'7'})");
+
+ session.run("MATCH (a:Target2),(b:Target2) WHERE a.number='4' AND b.number='5' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target2),(b:Target2) WHERE a.number='4' AND b.number='6' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target2),(b:Target2) WHERE a.number='4' AND b.number='7' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target2),(b:Target2) WHERE a.number='5' AND b.number='6' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target2),(b:Target2) WHERE a.number='6' AND b.number='7' CREATE (a)-[r:connected]->(b)");
+
+ //execute the plugin as a Cypher query and fetch the result
+ StatementResult result = session.run("CALL csb.subgraphIsomorphism('Pattern2','Target2')");
+
+ List resultList = result.list();//convert the result record stream to list
+
+ assertThat(resultList.size(), is(6)); //the result has correct number of subgraphs
+
+ assertThat(result.keys().size(), is(3));//the result has correct number of keys
+
+ assertThat(result.keys(), contains("subgraphIndex", "patternNode", "targetNode"));//the result has correct ordered keys
+
+ //split the actual result record into columns
+ List actualColumn1 = new ArrayList<>();
+
+ List actualColumn2 = new ArrayList<>();
+
+ List actualColumn3 = new ArrayList<>();
+
+ // fetch each column of the result record
+ resultList.forEach(record -> {
+
+ actualColumn1.add(record.get(0).asLong());
+
+ actualColumn2.add(record.get(1).toString());
+
+ actualColumn3.add(record.get(2).toString());
+
+ });
+
+ //construct the expected result columns
+ List expectedColumn1 = new ArrayList<>();
+
+ List expectedColumn2 = new ArrayList<>();
+
+ List expectedColumn3 = new ArrayList<>(Arrays.asList(
+ "node<5>", "node<4>", "node<3>",
+ "node<6>", "node<5>", "node<3>"));
+
+ for (Long i = 0L; i < 2; i++) {
+
+ for (int j = 0; j < 3; j++)
+ expectedColumn1.add(i);
+
+ expectedColumn2.addAll(Arrays.asList("node<2>", "node<1>", "node<0>"));
+
+ }
+
+
+ //check the actual result
+ assertThat(actualColumn1, equalTo(expectedColumn1));
+
+ assertThat(actualColumn2, equalTo(expectedColumn2));
+
+ assertThat(actualColumn3, equalTo(expectedColumn3));
+
+ session.close();
+
+ driver.close();
+ }
+
+ }
+
+ // This is the 3/3 tests
+ @Test
+ public void test3() throws Throwable {
+ try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build()
+ .withoutEncryption().toConfig())) {
+
+ Session session = driver.session();
+
+ //create the third pattern graph
+ session.run("CREATE (p:Pattern3 {number:'1'})");
+
+ session.run("CREATE (p:Pattern3 {number:'2'})");
+
+ session.run("CREATE (p:Pattern3 {number:'3'})");
+
+ session.run("CREATE (p:Pattern3 {number:'4'})");
+
+ session.run("MATCH (a:Pattern3),(b:Pattern3) WHERE a.number='1' AND b.number='2' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern3),(b:Pattern3) WHERE a.number='1' AND b.number='3' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern3),(b:Pattern3) WHERE a.number='2' AND b.number='3' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Pattern3),(b:Pattern3) WHERE a.number='3' AND b.number='4' CREATE (a)-[r:connected]->(b)");
+
+ //create the third target graph
+ session.run("CREATE (p:Target3 {number:'5'})");
+
+ session.run("CREATE (p:Target3 {number:'6'})");
+
+ session.run("CREATE (p:Target3 {number:'7'})");
+
+ session.run("CREATE (p:Target3 {number:'8'})");
+
+ session.run("CREATE (p:Target3 {number:'9'})");
+
+ session.run("CREATE (p:Target3 {number:'10'})");
+
+ session.run("MATCH (a:Target3),(b:Target3) WHERE a.number='5' AND b.number='6' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target3),(b:Target3) WHERE a.number='5' AND b.number='8' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target3),(b:Target3) WHERE a.number='7' AND b.number='8' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target3),(b:Target3) WHERE a.number='8' AND b.number='9' CREATE (a)-[r:connected]->(b)");
+
+ session.run("MATCH (a:Target3),(b:Target3) WHERE a.number='9' AND b.number='10' CREATE (a)-[r:connected]->(b)");
+
+ //execute the plugin as a Cypher query and fetch the result
+ StatementResult result = session.run("CALL csb.subgraphIsomorphism('Pattern3','Target3')");
+
+ List resultList = result.list();//convert the result record stream to list
+
+ assertThat(resultList.size(), is(0)); //the result should be empty: no matching subgraphs
+
+ assertThat(result.keys().size(), is(3));//the result has correct number of keys
+
+ assertThat(result.keys(), contains("subgraphIndex", "patternNode", "targetNode"));//the result has correct ordered keys
+
+ session.close();
+
+ driver.close();
+
+ }
+
+ }
+
+}
\ No newline at end of file