2020
2121import  static  apoc .util .TestContainerUtil .createEnterpriseDB ;
2222import  static  org .junit .Assert .assertEquals ;
23+ import  static  org .junit .Assert .assertFalse ;
2324import  static  org .junit .Assert .assertNotNull ;
25+ import  static  org .junit .Assert .assertNull ;
2426import  static  org .junit .Assert .assertTrue ;
2527import  static  org .neo4j .driver .Values .isoDuration ;
2628import  static  org .neo4j .driver .Values .point ;
2729
2830import  apoc .bolt .Bolt ;
2931import  apoc .cypher .Cypher ;
3032import  apoc .export .cypher .ExportCypher ;
33+ import  apoc .path .PathExplorer ;
34+ import  apoc .refactor .GraphRefactoring ;
3135import  apoc .util .Neo4jContainerExtension ;
3236import  apoc .util .TestContainerUtil ;
3337import  apoc .util .TestContainerUtil .ApocPackage ;
3943import  java .util .Collections ;
4044import  java .util .List ;
4145import  java .util .Map ;
46+ import  java .util .stream .Collectors ;
47+ import  org .junit .After ;
4248import  org .junit .AfterClass ;
4349import  org .junit .Assume ;
4450import  org .junit .BeforeClass ;
4551import  org .junit .ClassRule ;
4652import  org .junit .Test ;
53+ import  org .neo4j .driver .Session ;
54+ import  org .neo4j .graphdb .Entity ;
4755import  org .neo4j .graphdb .Label ;
4856import  org .neo4j .graphdb .Node ;
4957import  org .neo4j .graphdb .Relationship ;
58+ import  org .neo4j .graphdb .RelationshipType ;
5059import  org .neo4j .test .rule .DbmsRule ;
5160import  org .neo4j .test .rule .ImpermanentDbmsRule ;
5261
5564 * @since 29.08.17 
5665 */ 
5766public  class  BoltTest  {
67+     public  static  String  BOLT_URL ;
5868
5969    @ ClassRule 
6070    public  static  DbmsRule  db  = new  ImpermanentDbmsRule ();
6171
6272    private  static  Neo4jContainerExtension  neo4jContainer ;
73+     private  static  Session  session ;
6374
6475    @ BeforeClass 
6576    public  static  void  setUp () {
6677        neo4jContainer  = createEnterpriseDB (List .of (ApocPackage .FULL ), !TestUtil .isRunningInCI ())
6778                .withInitScript ("init_neo4j_bolt.cypher" );
6879        neo4jContainer .start ();
69-         TestUtil .registerProcedure (db , Bolt .class , ExportCypher .class , Cypher .class );
80+         TestUtil .registerProcedure (
81+                 db , Bolt .class , ExportCypher .class , Cypher .class , PathExplorer .class , GraphRefactoring .class );
82+         BOLT_URL  = getBoltUrl ().replaceAll ("'" , "" );
83+         session  = neo4jContainer .getSession ();
7084    }
7185
7286    @ AfterClass 
@@ -75,6 +89,223 @@ public static void tearDown() {
7589        db .shutdown ();
7690    }
7791
92+     @ After 
93+     public  void  after () {
94+         db .executeTransactionally ("MATCH (n) DETACH DELETE n" );
95+         session .writeTransaction (tx  -> tx .run ("MATCH (n:BoltStart), (m:Other) DETACH DELETE n, m" ));
96+     }
97+ 
98+     @ Test 
99+     public  void  testBoltLoadWithSubgraphAllQuery () {
100+         session .writeTransaction (
101+                 tx  -> tx .run ("CREATE (rootA:BoltStart {foobar: 'foobar'})-[:VIEWED]->(:Other {id: 1})" ));
102+ 
103+         // procedure with config virtual: false 
104+         String  boltQuery  = "MATCH (rootA:BoltStart {foobar: 'foobar'})\n "  + "WITH rootA\n " 
105+                 + "CALL apoc.path.subgraphAll(rootA, {relationshipFilter:'VIEWED>'})\n " 
106+                 + "YIELD nodes, relationships\n " 
107+                 + "RETURN nodes, relationships, rootA" ;
108+ 
109+         String  boltLoadQueryVirtualFalse  =
110+                 "CALL apoc.bolt.load($boltUrl, $boltQuery, {}, {virtual: false})\n "  + "YIELD row\n "  + "RETURN row" ;
111+ 
112+         TestUtil .testCall (
113+                 db ,
114+                 boltLoadQueryVirtualFalse ,
115+                 Map .of ("boltUrl" , BOLT_URL , "boltQuery" , boltQuery , "virtual" , false ),
116+                 this ::virtualFalseEntitiesAssertions );
117+ 
118+         // procedure with config virtual: true 
119+         String  boltLoadQueryVirtualTrue  =
120+                 "CALL apoc.bolt.load($boltUrl, $boltQuery, {}, {virtual: true}) YIELD row\n "  + "WITH row\n " 
121+                         + "WITH row.nodes AS nodes, row.relationships AS relationships, row.rootA AS rootA\n " 
122+                         + "CALL apoc.refactor.cloneSubgraph(nodes, relationships)\n " 
123+                         + "YIELD input, output, error\n " 
124+                         + "RETURN input, output, error;" ;
125+ 
126+         TestUtil .testResult (
127+                 db ,
128+                 boltLoadQueryVirtualTrue ,
129+                 Map .of ("boltUrl" , BOLT_URL , "boltQuery" , boltQuery , "virtual" , true ),
130+                 r  -> {
131+                     graphRefactorAssertions (r .next ());
132+                     graphRefactorAssertions (r .next ());
133+                     assertFalse (r .hasNext ());
134+                 });
135+ 
136+         // check that `apoc.refactor.cloneSubgraph` after `apoc.bolt.load` creates entities correctly 
137+         TestUtil .testCallCount (
138+                 db , "MATCH (rootA:BoltStart {foobar: 'foobar'})-[:VIEWED]->(:Other {id: 1}) RETURN *" , 1 );
139+     }
140+ 
141+     @ Test 
142+     public  void  testBoltFromLocalWithSubgraphAllQuery () {
143+         String  localStatement  = "RETURN 'foobar' AS foobar" ;
144+ 
145+         String  remoteStatement  =
146+                 "MERGE (rootA:BoltStart {foobar: foobar})-[:VIEWED]->(:Other {id: 1})\n "  + "WITH rootA\n " 
147+                         + "CALL apoc.path.subgraphAll(rootA, {relationshipFilter:'VIEWED>'})\n " 
148+                         + "YIELD nodes, relationships\n " 
149+                         + "RETURN nodes, relationships, rootA" ;
150+ 
151+         String  query  =
152+                 "CALL apoc.bolt.load.fromLocal($boltUrl, $localStatement, $remoteStatement, {virtual: $virtual, readOnly: false}) YIELD row\n " 
153+                         + "WITH row\n " 
154+                         + "RETURN row" ;
155+ 
156+         // procedure with config virtual: true 
157+         TestUtil .testCall (
158+                 db ,
159+                 query ,
160+                 Map .of (
161+                         "boltUrl" ,
162+                         BOLT_URL ,
163+                         "localStatement" ,
164+                         localStatement ,
165+                         "remoteStatement" ,
166+                         remoteStatement ,
167+                         "virtual" ,
168+                         true ),
169+                 this ::virtualTrueEntitiesAssertions );
170+ 
171+         // procedure with config virtual: false 
172+         TestUtil .testCall (
173+                 db ,
174+                 query ,
175+                 Map .of (
176+                         "boltUrl" ,
177+                         BOLT_URL ,
178+                         "localStatement" ,
179+                         localStatement ,
180+                         "remoteStatement" ,
181+                         remoteStatement ,
182+                         "virtual" ,
183+                         false ),
184+                 this ::virtualFalseEntitiesAssertions );
185+     }
186+ 
187+     private  void  virtualTrueEntitiesAssertions (Map <String , Object > r ) {
188+         Map <String , Object > row  = (Map <String , Object >) r .get ("row" );
189+         List <Node > nodes  = (List <Node >) row .get ("nodes" );
190+         assertEquals (2 , nodes .size ());
191+         List <Long > ids  = nodes .stream ().map (i  -> i .getId ()).collect (Collectors .toList ());
192+ 
193+         List <Relationship > relationships  = (List <Relationship >) row .get ("relationships" );
194+         assertEquals (1 , relationships .size ());
195+ 
196+         Relationship  rel  = relationships .get (0 );
197+         assertTrue (ids .contains (rel .getStartNodeId ()));
198+         assertTrue (ids .contains (rel .getEndNodeId ()));
199+         assertEquals (RelationshipType .withName ("VIEWED" ), rel .getType ());
200+ 
201+         Node  rootA  = (Node ) row .get ("rootA" );
202+         assertEquals (List .of (Label .label ("BoltStart" )), rootA .getLabels ());
203+         assertEquals (Map .of ("foobar" , "foobar" ), rootA .getAllProperties ());
204+     }
205+ 
206+     private  void  virtualFalseEntitiesAssertions (Map <String , Object > r ) {
207+         Map <String , Object > row  = (Map <String , Object >) r .get ("row" );
208+         List <Map > nodes  = (List <Map >) row .get ("nodes" );
209+         assertEquals (2 , nodes .size ());
210+         List <Long > ids  = nodes .stream ().map (i  -> (Long ) i .get ("id" )).collect (Collectors .toList ());
211+ 
212+         List <Map > relationships  = (List <Map >) row .get ("relationships" );
213+         assertEquals (1 , relationships .size ());
214+ 
215+         Map  rel  = relationships .get (0 );
216+         assertTrue (ids .contains ((Long ) rel .get ("start" )));
217+         assertTrue (ids .contains ((Long ) rel .get ("end" )));
218+         assertEquals ("VIEWED" , rel .get ("type" ));
219+ 
220+         Map  rootA  = (Map ) row .get ("rootA" );
221+         assertEquals (List .of ("BoltStart" ), rootA .get ("labels" ));
222+         assertEquals (Map .of ("foobar" , "foobar" ), rootA .get ("properties" ));
223+     }
224+ 
225+     private  void  graphRefactorAssertions (Map <String , Object > r ) {
226+         assertNull (r .get ("error" ));
227+         assertTrue (r .get ("input" ) instanceof  Long );
228+     }
229+ 
230+     @ Test 
231+     public  void  testBoltLoadReturningMapAndList () {
232+         session .writeTransaction (
233+                 tx  -> tx .run ("CREATE (rootA:BoltStart {foobar: 'foobar'})-[:VIEWED {id: 2}]->(:Other {id: 1})" ));
234+ 
235+         // procedure with config virtual: false 
236+         String  boltQuery  = "MATCH (start:BoltStart {foobar: 'foobar'})-[rel:VIEWED]->(end:Other)\n " 
237+                 + "WITH start, rel, end, [start, end, rel] as list\n " 
238+                 + "RETURN  start, rel, end, {keyOne: start, keyTwo: {innerKey: list}} as map, list" ;
239+ 
240+         String  boltLoadQuery  =
241+                 "CALL apoc.bolt.load($boltUrl, $boltQuery, {}, {virtual: $virtual})\n "  + "YIELD row\n "  + "RETURN row" ;
242+ 
243+         TestUtil .testCall (
244+                 db ,
245+                 boltLoadQuery ,
246+                 Map .of ("boltUrl" , BOLT_URL , "boltQuery" , boltQuery , "virtual" , true ),
247+                 this ::virtualTrueWithMapAndListAssertions );
248+ 
249+         TestUtil .testCall (
250+                 db ,
251+                 boltLoadQuery ,
252+                 Map .of ("boltUrl" , BOLT_URL , "boltQuery" , boltQuery , "virtual" , false ),
253+                 this ::virtualFalseWithMapAndListAssertions );
254+     }
255+ 
256+     private  void  virtualFalseWithMapAndListAssertions (Map <String , Object > r ) {
257+         Map <String , Object > row  = (Map <String , Object >) r .get ("row" );
258+ 
259+         Map  start  = (Map ) row .get ("start" );
260+         assertEquals ("NODE" , start .get ("entityType" ));
261+         Map  end  = (Map ) row .get ("end" );
262+         assertEquals ("NODE" , end .get ("entityType" ));
263+         Map  rel  = (Map ) row .get ("rel" );
264+         assertEquals ("RELATIONSHIP" , rel .get ("entityType" ));
265+ 
266+         List <Map > list  = (List <Map >) row .get ("list" );
267+         assertEquals (3 , list .size ());
268+ 
269+         assertEquals (start , list .get (0 ));
270+         assertEquals (end , list .get (1 ));
271+         assertEquals (rel , list .get (2 ));
272+ 
273+         Map  map  = (Map ) row .get ("map" );
274+         assertEquals (start , map .get ("keyOne" ));
275+ 
276+         Map  mapKeyTwo  = (Map ) map .get ("keyTwo" );
277+         assertEquals (list , mapKeyTwo .get ("innerKey" ));
278+     }
279+ 
280+     private  void  virtualTrueWithMapAndListAssertions (Map <String , Object > r ) {
281+         Map <String , Object > row  = (Map <String , Object >) r .get ("row" );
282+ 
283+         Node  start  = (Node ) row .get ("start" );
284+         assertEquals (List .of (Label .label ("BoltStart" )), start .getLabels ());
285+         assertEquals (Map .of ("foobar" , "foobar" ), start .getAllProperties ());
286+ 
287+         Node  end  = (Node ) row .get ("end" );
288+         assertEquals (List .of (Label .label ("Other" )), end .getLabels ());
289+         assertEquals (Map .of ("id" , 1L ), end .getAllProperties ());
290+ 
291+         Relationship  rel  = (Relationship ) row .get ("rel" );
292+         assertEquals (RelationshipType .withName ("VIEWED" ), rel .getType ());
293+         assertEquals (Map .of ("id" , 2L ), rel .getAllProperties ());
294+ 
295+         List <Entity > list  = (List <Entity >) row .get ("list" );
296+         assertEquals (3 , list .size ());
297+ 
298+         assertEquals (start , list .get (0 ));
299+         assertEquals (end , list .get (1 ));
300+         assertEquals (rel , list .get (2 ));
301+ 
302+         Map  map  = (Map ) row .get ("map" );
303+         assertEquals (start , map .get ("keyOne" ));
304+ 
305+         Map  mapKeyTwo  = (Map ) map .get ("keyTwo" );
306+         assertEquals (list , mapKeyTwo .get ("innerKey" ));
307+     }
308+ 
78309    @ Test 
79310    public  void  testNeo4jBolt () {
80311        final  String  uriDbBefore4  = System .getenv ("URI_DB_BEFORE_4" );
@@ -531,7 +762,7 @@ public void testLoadFromLocalStream() {
531762        assertEquals (1L , remoteCount );
532763    }
533764
534-     private  String  getBoltUrl () {
765+     private  static   String  getBoltUrl () {
535766        return  String .format (
536767                "'bolt://neo4j:%s@%s:%s'" ,
537768                TestContainerUtil .password , neo4jContainer .getContainerIpAddress (), neo4jContainer .getMappedPort (7687 ));
0 commit comments