View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server.rest.web;
21  
22  import static org.hamcrest.Matchers.containsString;
23  import static org.hamcrest.Matchers.greaterThanOrEqualTo;
24  import static org.hamcrest.Matchers.hasKey;
25  import static org.hamcrest.Matchers.is;
26  import static org.junit.Assert.assertEquals;
27  import static org.junit.Assert.assertFalse;
28  import static org.junit.Assert.assertNotNull;
29  import static org.junit.Assert.assertNull;
30  import static org.junit.Assert.assertThat;
31  import static org.junit.Assert.assertTrue;
32  import static org.mockito.Mockito.mock;
33  import static org.mockito.Mockito.when;
34  
35  import java.io.File;
36  import java.io.IOException;
37  import java.io.UnsupportedEncodingException;
38  import java.net.URI;
39  import java.net.URISyntaxException;
40  import java.util.Collection;
41  import java.util.Collections;
42  import java.util.HashMap;
43  import java.util.List;
44  import java.util.Map;
45  
46  import javax.ws.rs.core.HttpHeaders;
47  import javax.ws.rs.core.Response;
48  import javax.ws.rs.core.Response.Status;
49  import javax.ws.rs.core.UriInfo;
50  
51  import org.junit.After;
52  import org.junit.Before;
53  import org.junit.Test;
54  import org.neo4j.helpers.collection.MapUtil;
55  import org.neo4j.server.ServerTestUtils;
56  import org.neo4j.server.database.Database;
57  import org.neo4j.server.database.DatabaseBlockedException;
58  import org.neo4j.server.rest.domain.GraphDbHelper;
59  import org.neo4j.server.rest.domain.JsonHelper;
60  import org.neo4j.server.rest.domain.JsonParseException;
61  import org.neo4j.server.rest.domain.TraverserReturnType;
62  import org.neo4j.server.rest.repr.BadInputException;
63  import org.neo4j.server.rest.repr.RelationshipRepresentationTest;
64  import org.neo4j.server.rest.repr.formats.JsonFormat;
65  import org.neo4j.server.rest.web.DatabaseActions.RelationshipDirection;
66  import org.neo4j.server.rest.web.RestfulGraphDatabase.AmpersandSeparatedCollection;
67  
68  public class RestfulGraphDatabaseTest
69  {
70      private static final String BASE_URI = "http://neo4j.org/";
71      private RestfulGraphDatabase service;
72      private Database database;
73      private GraphDbHelper helper;
74      private EntityOutputFormat output;
75      private String databasePath;
76  
77      @Before
78      public void doBefore() throws IOException
79      {
80          databasePath = ServerTestUtils.createTempDir().getAbsolutePath();
81          database = new Database( ServerTestUtils.EMBEDDED_GRAPH_DATABASE_FACTORY, databasePath );
82          helper = new GraphDbHelper( database );
83          output = new EntityOutputFormat( new JsonFormat(), URI.create( BASE_URI ), null );
84          service = new RestfulGraphDatabase( uriInfo(), database, new JsonFormat(), output );
85      }
86  
87      @After
88      public void shutdownDatabase() throws IOException
89      {
90          this.database.shutdown();
91          org.apache.commons.io.FileUtils.forceDelete( new File(databasePath) );
92      }
93  
94      private UriInfo uriInfo()
95      {
96          UriInfo mockUriInfo = mock( UriInfo.class );
97          try
98          {
99              when( mockUriInfo.getBaseUri() ).thenReturn( new URI( BASE_URI ) );
100         } catch ( URISyntaxException e )
101         {
102             throw new RuntimeException( e );
103         }
104 
105         return mockUriInfo;
106     }
107 
108     private static String entityAsString( Response response )
109     {
110         byte[] bytes = (byte[]) response.getEntity();
111         try
112         {
113             return new String( bytes, "UTF-8" );
114         } catch ( UnsupportedEncodingException e )
115         {
116             throw new RuntimeException( "Could not decode UTF-8", e );
117         }
118     }
119 
120     @Test
121     public void shouldRespondWith201LocationHeaderAndNodeRepresentationInJSONWhenEmptyNodeCreated() throws Exception
122     {
123         Response response = service.createNode( null );
124 
125         assertEquals( 201, response.getStatus() );
126         assertNotNull( response.getMetadata().get( "Location" ).get( 0 ) );
127         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
128         String json = entityAsString( response );
129 
130         Map<String, Object> map = JsonHelper.jsonToMap( json );
131 
132         assertNotNull( map );
133 
134         assertTrue( map.containsKey( "self" ) );
135     }
136 
137     @Test
138     public void shouldRespondWith201LocationHeaderAndNodeRepresentationInJSONWhenPopulatedNodeCreated() throws Exception
139     {
140         Response response = service.createNode( "{\"foo\" : \"bar\"}" );
141 
142         assertEquals( 201, response.getStatus() );
143         assertNotNull( response.getMetadata().get( "Location" ).get( 0 ) );
144         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
145         String json = entityAsString( response );
146 
147         Map<String, Object> map = JsonHelper.jsonToMap( json );
148 
149         assertNotNull( map );
150 
151         assertTrue( map.containsKey( "self" ) );
152 
153         @SuppressWarnings("unchecked")
154         Map<String, Object> data = (Map<String, Object>) map.get( "data" );
155 
156         assertEquals( "bar", data.get( "foo" ) );
157     }
158 
159     @Test
160     @SuppressWarnings("unchecked")
161     public void shouldRespondWith201LocationHeaderAndNodeRepresentationInJSONWhenPopulatedNodeCreatedWithArrays() throws Exception
162     {
163         Response response = service.createNode( "{\"foo\" : [\"bar\", \"baz\"] }" );
164 
165         assertEquals( 201, response.getStatus() );
166         assertNotNull( response.getMetadata().get( "Location" ).get( 0 ) );
167         String json = entityAsString( response );
168 
169         Map<String, Object> map = JsonHelper.jsonToMap( json );
170 
171         assertNotNull( map );
172 
173         Map<String, Object> data = (Map<String, Object>) map.get( "data" );
174 
175         List<String> foo = (List<String>) data.get( "foo" );
176         assertNotNull( foo );
177         assertEquals( 2, foo.size() );
178     }
179 
180     @Test
181     public void shouldRespondWith400WhenNodeCreatedWithUnsupportedPropertyData() throws DatabaseBlockedException
182     {
183         Response response = service.createNode( "{\"foo\" : {\"bar\" : \"baz\"}}" );
184 
185         assertEquals( 400, response.getStatus() );
186     }
187 
188     @Test
189     public void shouldRespondWith400WhenNodeCreatedWithInvalidJSON() throws DatabaseBlockedException
190     {
191         Response response = service.createNode( "this:::isNot::JSON}" );
192 
193         assertEquals( 400, response.getStatus() );
194     }
195 
196     @Test
197     public void shouldRespondWith200AndNodeRepresentationInJSONWhenNodeRequested() throws Exception
198     {
199         Response response = service.getNode( helper.createNode() );
200         assertEquals( 200, response.getStatus() );
201         String json = entityAsString( response );
202         Map<String, Object> map = JsonHelper.jsonToMap( json );
203         assertNotNull( map );
204         assertTrue( map.containsKey( "self" ) );
205     }
206 
207     @Test
208     public void shouldRespondWith404WhenRequestedNodeDoesNotExist() throws Exception
209     {
210         Response response = service.getNode( 9000000000000L );
211         assertEquals( 404, response.getStatus() );
212     }
213 
214     @Test
215     public void shouldRespondWith204AfterSettingPropertiesOnExistingNode() throws Exception
216     {
217         Response response = service.setAllNodeProperties( helper.createNode(),
218                 "{\"foo\" : \"bar\", \"a-boolean\": true, \"boolean-array\": [true, false, false]}" );
219         assertEquals( 204, response.getStatus() );
220     }
221 
222     @Test
223     public void shouldRespondWith404WhenSettingPropertiesOnNodeThatDoesNotExist() throws Exception
224     {
225         Response response = service.setAllNodeProperties( 9000000000000L, "{\"foo\" : \"bar\"}" );
226         assertEquals( 404, response.getStatus() );
227     }
228 
229     @Test
230     public void shouldRespondWith400WhenTransferringCorruptJsonPayload() throws Exception
231     {
232         Response response = service.setAllNodeProperties( helper.createNode(),
233                 "{\"foo\" : bad-json-here \"bar\"}" );
234         assertEquals( 400, response.getStatus() );
235     }
236 
237     @Test
238     public void shouldRespondWith400WhenTransferringIncompatibleJsonPayload() throws Exception
239     {
240         Response response = service.setAllNodeProperties( helper.createNode(),
241                 "{\"foo\" : {\"bar\" : \"baz\"}}" );
242         assertEquals( 400, response.getStatus() );
243     }
244 
245     @Test
246     public void shouldRespondWith200ForGetNodeProperties() throws Exception
247     {
248         long nodeId = helper.createNode();
249         Map<String, Object> properties = new HashMap<String, Object>();
250         properties.put( "foo", "bar" );
251         helper.setNodeProperties( nodeId, properties );
252         Response response = service.getAllNodeProperties( nodeId );
253         assertEquals( 200, response.getStatus() );
254         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
255     }
256 
257     @Test
258     public void shouldRespondWith204ForGetNoNodeProperties() throws Exception
259     {
260         long nodeId = helper.createNode();
261         Response response = service.getAllNodeProperties( nodeId );
262         assertEquals( 204, response.getStatus() );
263     }
264 
265     @Test
266     public void shouldGetPropertiesForGetNodeProperties() throws Exception
267     {
268         long nodeId = helper.createNode();
269         Map<String, Object> properties = new HashMap<String, Object>();
270         properties.put( "foo", "bar" );
271         properties.put( "number", 15 );
272         properties.put( "double", 15.7 );
273         helper.setNodeProperties( nodeId, properties );
274         Response response = service.getAllNodeProperties( nodeId );
275         String jsonBody = entityAsString( response );
276         Map<String, Object> readProperties = JsonHelper.jsonToMap( jsonBody );
277         assertEquals( properties, readProperties );
278     }
279 
280     @Test
281     public void shouldRespondWith204OnSuccessfulDelete() throws DatabaseBlockedException
282     {
283         long id = helper.createNode();
284 
285         Response response = service.deleteNode( id );
286 
287         assertEquals( 204, response.getStatus() );
288     }
289 
290     @Test
291     public void shouldRespondWith409IfNodeCannotBeDeleted() throws DatabaseBlockedException
292     {
293         long id = helper.createNode();
294         helper.createRelationship( "LOVES", id, helper.createNode() );
295 
296         Response response = service.deleteNode( id );
297 
298         assertEquals( 409, response.getStatus() );
299     }
300 
301     @Test
302     public void shouldRespondWith404IfNodeToBeDeletedDoesNotExist() throws DatabaseBlockedException
303     {
304         long nonExistentId = 999999;
305         Response response = service.deleteNode( nonExistentId );
306 
307         assertEquals( 404, response.getStatus() );
308     }
309 
310     @Test
311     public void shouldRespondWith204ForSetNodeProperty() throws DatabaseBlockedException
312     {
313         long nodeId = helper.createNode();
314         String key = "foo";
315         String json = "\"bar\"";
316         Response response = service.setNodeProperty( nodeId, key, json );
317         assertEquals( 204, response.getStatus() );
318     }
319 
320     @Test
321     public void shouldSetRightValueForSetNodeProperty() throws DatabaseBlockedException
322     {
323         long nodeId = helper.createNode();
324         String key = "foo";
325         String value = "bar";
326         String json = "\"" + value + "\"";
327         service.setNodeProperty( nodeId, key, json );
328         Map<String, Object> readProperties = helper.getNodeProperties( nodeId );
329         assertEquals( Collections.singletonMap( key, value ), readProperties );
330     }
331 
332     @Test
333     public void shouldRespondWith404ForSetNodePropertyOnNonExistingNode() throws DatabaseBlockedException
334     {
335         String key = "foo";
336         String json = "\"bar\"";
337         Response response = service.setNodeProperty( 999999, key, json );
338         assertEquals( 404, response.getStatus() );
339     }
340 
341     @Test
342     public void shouldRespondWith400ForSetNodePropertyWithInvalidJson() throws DatabaseBlockedException
343     {
344         String key = "foo";
345         String json = "{invalid json";
346         Response response = service.setNodeProperty( 999999, key, json );
347         assertEquals( 400, response.getStatus() );
348     }
349 
350     @Test
351     public void shouldRespondWith404ForGetNonExistentNodeProperty() throws DatabaseBlockedException
352     {
353         long nodeId = helper.createNode();
354         Response response = service.getNodeProperty( nodeId, "foo" );
355         assertEquals( 404, response.getStatus() );
356     }
357 
358     @Test
359     public void shouldRespondWith404ForGetNodePropertyOnNonExistentNode() throws DatabaseBlockedException
360     {
361         long nodeId = 999999;
362         Response response = service.getNodeProperty( nodeId, "foo" );
363         assertEquals( 404, response.getStatus() );
364     }
365 
366     @Test
367     public void shouldRespondWith200ForGetNodeProperty() throws DatabaseBlockedException
368     {
369         long nodeId = helper.createNode();
370         String key = "foo";
371         Object value = "bar";
372         helper.setNodeProperties( nodeId, Collections.singletonMap( key, value ) );
373         Response response = service.getNodeProperty( nodeId, "foo" );
374         assertEquals( 200, response.getStatus() );
375         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
376     }
377 
378     @Test
379     public void shouldReturnCorrectValueForGetNodeProperty() throws Exception
380     {
381         long nodeId = helper.createNode();
382         String key = "foo";
383         Object value = "bar";
384         helper.setNodeProperties( nodeId, Collections.singletonMap( key, value ) );
385         Response response = service.getNodeProperty( nodeId, "foo" );
386         assertEquals( JsonHelper.createJsonFrom( value ), entityAsString( response ) );
387     }
388 
389     @Test
390     public void shouldRespondWith201AndLocationWhenRelationshipIsCreatedWithoutProperties() throws DatabaseBlockedException
391     {
392         long startNode = helper.createNode();
393         long endNode = helper.createNode();
394         Response response = service.createRelationship( startNode, "{\"to\" : \"" + BASE_URI
395                 + endNode
396                 + "\", \"type\" : \"LOVES\"}" );
397         assertEquals( 201, response.getStatus() );
398         assertNotNull( response.getMetadata().get( "Location" ).get( 0 ) );
399     }
400 
401     @Test
402     public void shouldRespondWith201AndLocationWhenRelationshipIsCreatedWithProperties() throws DatabaseBlockedException
403     {
404         long startNode = helper.createNode();
405         long endNode = helper.createNode();
406         Response response = service.createRelationship( startNode,
407                 "{\"to\" : \"" + BASE_URI + endNode
408                         + "\", \"type\" : \"LOVES\", \"properties\" : {\"foo\" : \"bar\"}}" );
409         assertEquals( 201, response.getStatus() );
410         assertNotNull( response.getMetadata().get( "Location" ).get( 0 ) );
411     }
412 
413     @Test
414     public void shouldReturnRelationshipRepresentationWhenCreatingRelationship() throws Exception
415     {
416         long startNode = helper.createNode();
417         long endNode = helper.createNode();
418         Response response = service.createRelationship( startNode,
419                 "{\"to\" : \"" + BASE_URI + endNode
420                         + "\", \"type\" : \"LOVES\", \"data\" : {\"foo\" : \"bar\"}}" );
421         Map<String, Object> map = JsonHelper.jsonToMap( entityAsString( response ) );
422         assertNotNull( map );
423         assertTrue( map.containsKey( "self" ) );
424         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
425 
426         @SuppressWarnings("unchecked")
427         Map<String, Object> data = (Map<String, Object>) map.get( "data" );
428 
429         assertEquals( "bar", data.get( "foo" ) );
430     }
431 
432     @Test
433     public void shouldRespondWith404WhenTryingToCreateRelationshipFromNonExistentNode() throws DatabaseBlockedException
434     {
435         long nodeId = helper.createNode();
436         Response response = service.createRelationship( nodeId * 1000,
437                 "{\"to\" : \"" + BASE_URI + nodeId
438                         + "\", \"type\" : \"LOVES\"}" );
439         assertEquals( 404, response.getStatus() );
440     }
441 
442     @Test
443     public void shouldRespondWith400WhenTryingToCreateRelationshipToNonExistentNode() throws DatabaseBlockedException
444     {
445         long nodeId = helper.createNode();
446         Response response = service.createRelationship( nodeId, "{\"to\" : \"" + BASE_URI
447                 + (nodeId * 1000)
448                 + "\", \"type\" : \"LOVES\"}" );
449         assertEquals( 400, response.getStatus() );
450     }
451 
452     @Test
453     public void shouldRespondWith400WhenTryingToCreateRelationshipToStartNode() throws DatabaseBlockedException
454     {
455         long nodeId = helper.createNode();
456         Response response = service.createRelationship( nodeId, "{\"to\" : \"" + BASE_URI + nodeId
457                 + "\", \"type\" : \"LOVES\"}" );
458         assertEquals( 400, response.getStatus() );
459     }
460 
461     @Test
462     public void shouldRespondWith400WhenTryingToCreateRelationshipWithBadJson() throws DatabaseBlockedException
463     {
464         long startNode = helper.createNode();
465         long endNode = helper.createNode();
466         Response response = service.createRelationship( startNode,
467                 "{\"to\" : \"" + BASE_URI + endNode
468                         + "\", \"type\" ***and junk*** : \"LOVES\"}" );
469         assertEquals( 400, response.getStatus() );
470     }
471 
472     @Test
473     public void shouldRespondWith400WhenTryingToCreateRelationshipWithUnsupportedProperties() throws DatabaseBlockedException
474     {
475         long startNode = helper.createNode();
476         long endNode = helper.createNode();
477         Response response = service.createRelationship( startNode,
478                 "{\"to\" : \"" + BASE_URI + endNode
479                         + "\", \"type\" : \"LOVES\", \"data\" : {\"foo\" : {\"bar\" : \"baz\"}}}" );
480         assertEquals( 400, response.getStatus() );
481     }
482 
483     @Test
484     public void shouldRespondWith204ForRemoveNodeProperties() throws DatabaseBlockedException
485     {
486         long nodeId = helper.createNode();
487         Map<String, Object> properties = new HashMap<String, Object>();
488         properties.put( "foo", "bar" );
489         properties.put( "number", 15 );
490         helper.setNodeProperties( nodeId, properties );
491         Response response = service.deleteAllNodeProperties( nodeId );
492         assertEquals( 204, response.getStatus() );
493     }
494 
495     @Test
496     public void shouldBeAbleToRemoveNodeProperties() throws DatabaseBlockedException
497     {
498         long nodeId = helper.createNode();
499         Map<String, Object> properties = new HashMap<String, Object>();
500         properties.put( "foo", "bar" );
501         properties.put( "number", 15 );
502         helper.setNodeProperties( nodeId, properties );
503         service.deleteAllNodeProperties( nodeId );
504         assertEquals( true, helper.getNodeProperties( nodeId ).isEmpty() );
505     }
506 
507     @Test
508     public void shouldRespondWith404ForRemoveNodePropertiesForNonExistingNode() throws DatabaseBlockedException
509     {
510         long nodeId = 999999;
511         Response response = service.deleteAllNodeProperties( nodeId );
512         assertEquals( 404, response.getStatus() );
513     }
514 
515     @Test
516     public void shouldBeAbleToRemoveNodeProperty() throws DatabaseBlockedException
517     {
518         long nodeId = helper.createNode();
519         Map<String, Object> properties = new HashMap<String, Object>();
520         properties.put( "foo", "bar" );
521         properties.put( "number", 15 );
522         helper.setNodeProperties( nodeId, properties );
523         service.deleteNodeProperty( nodeId, "foo" );
524         assertEquals( Collections.singletonMap( "number", (Object) new Integer( 15 ) ), helper.getNodeProperties( nodeId ) );
525     }
526 
527     @Test
528     public void shouldGet404WhenRemovingNonExistingProperty() throws DatabaseBlockedException
529     {
530         long nodeId = helper.createNode();
531         Map<String, Object> properties = new HashMap<String, Object>();
532         properties.put( "foo", "bar" );
533         properties.put( "number", 15 );
534         helper.setNodeProperties( nodeId, properties );
535         Response response = service.deleteNodeProperty( nodeId, "baz" );
536         assertEquals( 404, response.getStatus() );
537     }
538 
539     @Test
540     public void shouldGet404WhenRemovingPropertyFromNonExistingNode() throws DatabaseBlockedException
541     {
542         long nodeId = 999999;
543         Response response = service.deleteNodeProperty( nodeId, "foo" );
544         assertEquals( 404, response.getStatus() );
545     }
546 
547     @Test
548     public void shouldGet200WhenRetrievingARelationshipFromANode() throws DatabaseBlockedException
549     {
550         long relationshipId = helper.createRelationship( "BEATS" );
551         Response response = service.getRelationship( relationshipId );
552         assertEquals( 200, response.getStatus() );
553         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
554     }
555 
556     @Test
557     public void shouldGet404WhenRetrievingRelationshipThatDoesNotExist() throws DatabaseBlockedException
558     {
559         Response response = service.getRelationship( 999999 );
560         assertEquals( 404, response.getStatus() );
561     }
562 
563     @Test
564     public void shouldRespondWith200AndDataForGetRelationshipProperties() throws Exception
565     {
566         long relationshipId = helper.createRelationship( "knows" );
567         Map<String, Object> properties = new HashMap<String, Object>();
568         properties.put( "foo", "bar" );
569         helper.setRelationshipProperties( relationshipId, properties );
570         Response response = service.getAllRelationshipProperties( relationshipId );
571         assertEquals( 200, response.getStatus() );
572         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
573         Map<String, Object> readProperties = JsonHelper.jsonToMap( entityAsString( response ) );
574         assertEquals( properties, readProperties );
575     }
576 
577     @Test
578     public void shouldRespondWith204ForGetNoRelationshipProperties() throws DatabaseBlockedException
579     {
580         long relationshipId = helper.createRelationship( "knows" );
581         Response response = service.getAllRelationshipProperties( relationshipId );
582         assertEquals( 204, response.getStatus() );
583     }
584 
585     @Test
586     public void shouldGet200WhenSuccessfullyRetrievedPropertyOnRelationship() throws DatabaseBlockedException, PropertyValueException
587     {
588 
589         long relationshipId = helper.createRelationship( "knows" );
590         Map<String, Object> properties = new HashMap<String, Object>();
591         properties.put( "some-key", "some-value" );
592         helper.setRelationshipProperties( relationshipId, properties );
593 
594         Response response = service.getRelationshipProperty( relationshipId, "some-key" );
595 
596         assertEquals( 200, response.getStatus() );
597         assertEquals( "some-value", JsonHelper.jsonToSingleValue( entityAsString( response ) ) );
598         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
599     }
600 
601     @Test
602     public void shouldGet404WhenCannotResolveAPropertyOnRelationship() throws DatabaseBlockedException
603     {
604         long relationshipId = helper.createRelationship( "knows" );
605         Response response = service.getRelationshipProperty( relationshipId, "some-key" );
606         assertEquals( 404, response.getStatus() );
607     }
608 
609     @Test
610     public void shouldGet204WhenRemovingARelationship() throws DatabaseBlockedException
611     {
612         long relationshipId = helper.createRelationship( "KNOWS" );
613 
614         Response response = service.deleteRelationship( relationshipId );
615         assertEquals( 204, response.getStatus() );
616     }
617 
618     @Test
619     public void shouldGet404WhenRemovingNonExistentRelationship() throws DatabaseBlockedException
620     {
621         long relationshipId = helper.createRelationship( "KNOWS" );
622 
623         Response response = service.deleteRelationship( relationshipId + 1 * 1000 );
624         assertEquals( 404, response.getStatus() );
625     }
626 
627     @Test
628     public void shouldRespondWith200AndListOfRelationshipRepresentationsWhenGettingRelationshipsForANode() throws DatabaseBlockedException, JsonParseException
629     {
630         long nodeId = helper.createNode();
631         helper.createRelationship( "LIKES", nodeId, helper.createNode() );
632         helper.createRelationship( "LIKES", helper.createNode(), nodeId );
633         helper.createRelationship( "HATES", nodeId, helper.createNode() );
634 
635         Response response = service.getNodeRelationships( nodeId, RelationshipDirection.all,
636                 new AmpersandSeparatedCollection( "" ) );
637         assertEquals( 200, response.getStatus() );
638         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
639         verifyRelReps( 3, entityAsString( response ) );
640 
641         response = service.getNodeRelationships( nodeId, RelationshipDirection.in,
642                 new AmpersandSeparatedCollection( "" ) );
643         assertEquals( 200, response.getStatus() );
644         verifyRelReps( 1, entityAsString( response ) );
645 
646         response = service.getNodeRelationships( nodeId, RelationshipDirection.out,
647                 new AmpersandSeparatedCollection( "" ) );
648         assertEquals( 200, response.getStatus() );
649         verifyRelReps( 2, entityAsString( response ) );
650 
651         response = service.getNodeRelationships( nodeId, RelationshipDirection.out,
652                 new AmpersandSeparatedCollection( "LIKES&HATES" ) );
653         assertEquals( 200, response.getStatus() );
654         verifyRelReps( 2, entityAsString( response ) );
655 
656         response = service.getNodeRelationships( nodeId, RelationshipDirection.all,
657                 new AmpersandSeparatedCollection( "LIKES" ) );
658         assertEquals( 200, response.getStatus() );
659         verifyRelReps( 2, entityAsString( response ) );
660     }
661 
662     @Test
663     public void shouldNotReturnDuplicatesIfSameTypeSpecifiedMoreThanOnce() throws DatabaseBlockedException, PropertyValueException
664     {
665         long nodeId = helper.createNode();
666         helper.createRelationship( "LIKES", nodeId, helper.createNode() );
667         Response response = service.getNodeRelationships( nodeId, RelationshipDirection.all,
668                 new AmpersandSeparatedCollection( "LIKES&LIKES" ) );
669         Collection<?> array = (Collection<?>) JsonHelper.jsonToSingleValue( entityAsString( response ) );
670         assertEquals( 1, array.size() );
671     }
672 
673     private void verifyRelReps( int expectedSize, String entity ) throws JsonParseException
674     {
675         List<Map<String, Object>> relreps = JsonHelper.jsonToList( entity );
676         assertEquals( expectedSize, relreps.size() );
677         for ( Map<String, Object> relrep : relreps )
678         {
679             RelationshipRepresentationTest.verifySerialisation( relrep );
680         }
681     }
682 
683     @Test
684     public void shouldRespondWith200AndEmptyListOfRelationshipRepresentationsWhenGettingRelationshipsForANodeWithoutRelationships()
685             throws DatabaseBlockedException, JsonParseException
686     {
687         long nodeId = helper.createNode();
688 
689         Response response = service.getNodeRelationships( nodeId, RelationshipDirection.all,
690                 new AmpersandSeparatedCollection( "" ) );
691         assertEquals( 200, response.getStatus() );
692         verifyRelReps( 0, entityAsString( response ) );
693         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
694     }
695 
696     @Test
697     public void shouldRespondWith404WhenGettingIncomingRelationshipsForNonExistingNode() throws DatabaseBlockedException
698     {
699         Response response = service.getNodeRelationships( 999999, RelationshipDirection.all,
700                 new AmpersandSeparatedCollection( "" ) );
701         assertEquals( 404, response.getStatus() );
702     }
703 
704     @Test
705     public void shouldRespondWith204AndSetCorrectDataWhenSettingRelationshipProperties() throws DatabaseBlockedException
706     {
707         long relationshipId = helper.createRelationship( "KNOWS" );
708         String json = "{\"name\": \"Mattias\", \"age\": 30}";
709         Response response = service.setAllRelationshipProperties( relationshipId, json );
710         assertEquals( 204, response.getStatus() );
711         Map<String, Object> setProperties = new HashMap<String, Object>();
712         setProperties.put( "name", "Mattias" );
713         setProperties.put( "age", 30 );
714         assertEquals( setProperties, helper.getRelationshipProperties( relationshipId ) );
715     }
716 
717     @Test
718     public void shouldRespondWith400WhenSettingRelationshipPropertiesWithBadJson() throws DatabaseBlockedException
719     {
720         long relationshipId = helper.createRelationship( "KNOWS" );
721         String json = "{\"name: \"Mattias\", \"age\": 30}";
722         Response response = service.setAllRelationshipProperties( relationshipId, json );
723         assertEquals( 400, response.getStatus() );
724     }
725 
726     @Test
727     public void shouldRespondWith404WhenSettingRelationshipPropertiesOnNonExistingRelationship() throws DatabaseBlockedException
728     {
729         long relationshipId = 99999999;
730         String json = "{\"name\": \"Mattias\", \"age\": 30}";
731         Response response = service.setAllRelationshipProperties( relationshipId, json );
732         assertEquals( 404, response.getStatus() );
733     }
734 
735     @Test
736     public void shouldRespondWith204AndSetCorrectDataWhenSettingRelationshipProperty() throws DatabaseBlockedException
737     {
738         long relationshipId = helper.createRelationship( "KNOWS" );
739         String key = "name";
740         Object value = "Mattias";
741         String json = "\"" + value + "\"";
742         Response response = service.setRelationshipProperty( relationshipId, key, json );
743         assertEquals( 204, response.getStatus() );
744         assertEquals( value, helper.getRelationshipProperties( relationshipId ).get( "name" ) );
745     }
746 
747     @Test
748     public void shouldRespondWith400WhenSettingRelationshipPropertyWithBadJson() throws DatabaseBlockedException
749     {
750         long relationshipId = helper.createRelationship( "KNOWS" );
751         String json = "}Mattias";
752         Response response = service.setRelationshipProperty( relationshipId, "name", json );
753         assertEquals( 400, response.getStatus() );
754     }
755 
756     @Test
757     public void shouldRespondWith404WhenSettingRelationshipPropertyOnNonExistingRelationship() throws DatabaseBlockedException
758     {
759         long relationshipId = 99999999;
760         String json = "\"Mattias\"";
761         Response response = service.setRelationshipProperty( relationshipId, "name", json );
762         assertEquals( 404, response.getStatus() );
763     }
764 
765     @Test
766     public void shouldRespondWith204WhenSuccessfullyRemovedRelationshipProperties() throws DatabaseBlockedException
767     {
768         long relationshipId = helper.createRelationship( "KNOWS" );
769         helper.setRelationshipProperties( relationshipId, Collections.singletonMap( "foo", (Object) "bar" ) );
770 
771         Response response = service.deleteAllRelationshipProperties( relationshipId );
772         assertEquals( 204, response.getStatus() );
773     }
774 
775     @Test
776     public void shouldRespondWith204WhenSuccessfullyRemovedRelationshipPropertiesWhichAreEmpty() throws DatabaseBlockedException
777     {
778         long relationshipId = helper.createRelationship( "KNOWS" );
779 
780         Response response = service.deleteAllRelationshipProperties( relationshipId );
781         assertEquals( 204, response.getStatus() );
782     }
783 
784     @Test
785     public void shouldRespondWith404WhenNoRelationshipFromWhichToRemoveProperties() throws DatabaseBlockedException
786     {
787         long relationshipId = helper.createRelationship( "KNOWS" );
788 
789         Response response = service.deleteAllRelationshipProperties( relationshipId + 1 * 1000 );
790         assertEquals( 404, response.getStatus() );
791     }
792 
793     @Test
794     public void shouldRespondWith204WhenRemovingRelationshipProperty() throws DatabaseBlockedException
795     {
796         long relationshipId = helper.createRelationship( "KNOWS" );
797         helper.setRelationshipProperties( relationshipId, Collections.singletonMap( "foo", (Object) "bar" ) );
798 
799         Response response = service.deleteRelationshipProperty( relationshipId, "foo" );
800 
801         assertEquals( 204, response.getStatus() );
802     }
803 
804     @Test
805     public void shouldRespondWith404WhenRemovingRelationshipPropertyWhichDoesNotExist() throws DatabaseBlockedException
806     {
807         long relationshipId = helper.createRelationship( "KNOWS" );
808         Response response = service.deleteRelationshipProperty( relationshipId, "foo" );
809         assertEquals( 404, response.getStatus() );
810     }
811 
812     @Test
813     public void shouldRespondWith404WhenNoRelationshipFromWhichToRemoveProperty() throws DatabaseBlockedException
814     {
815         long relationshipId = helper.createRelationship( "KNOWS" );
816 
817         Response response = service.deleteRelationshipProperty( relationshipId * 1000, "some-key" );
818         assertEquals( 404, response.getStatus() );
819     }
820 
821     @Test
822     public void shouldRespondWithNoContentNoNodeIndexesExist()
823     {
824         Response response = service.getNodeIndexRoot();
825         assertEquals( 204, response.getStatus() );
826     }
827 
828     @Test
829     public void shouldRespondWithAvailableIndexNodeRoots() throws BadInputException
830     {
831         String indexName = "someNodes";
832         helper.createNodeIndex( indexName );
833         Response response = service.getNodeIndexRoot();
834         assertEquals( 200, response.getStatus() );
835 
836         Map<String, Object> resultAsMap = output.getResultAsMap();
837         assertThat( resultAsMap.size(), is( 1 ) );
838         assertThat( resultAsMap, hasKey( indexName ) );
839     }
840 
841     @Test
842     public void shouldRespondWithNoContentWhenNoRelationshipIndexesExist()
843     {
844         Response response = service.getRelationshipIndexRoot();
845         assertEquals( 204, response.getStatus() );
846     }
847 
848     @Test
849     public void shouldRespondWithAvailableIndexRelationshipRoots() throws BadInputException
850     {
851         String indexName = "someRelationships";
852         helper.createRelationshipIndex( indexName );
853         Response response = service.getRelationshipIndexRoot();
854         assertEquals( 200, response.getStatus() );
855         Map<String, Object> resultAsMap = output.getResultAsMap();
856         assertThat( resultAsMap.size(), is( 1 ) );
857         assertThat( resultAsMap, hasKey( indexName ) );
858     }
859 
860     @Test
861     public void shouldBeAbleToGetRoot() throws JsonParseException
862     {
863         Response response = service.getRoot();
864         assertEquals( 200, response.getStatus() );
865         String entity = entityAsString( response );
866         Map<String, Object> map = JsonHelper.jsonToMap( entity );
867         assertNotNull( map.get( "node" ) );
868         assertNotNull( map.get( "reference_node" ) );
869         assertNotNull( map.get( "node_index" ) );
870         assertNotNull( map.get( "extensions_info" ) );
871         assertNotNull( map.get( "relationship_index" ) );
872         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
873     }
874 
875     @Test
876     public void shouldBeAbleToGetRootWhenNoReferenceNodePresent() throws JsonParseException
877     {
878         helper.deleteNode( 0l );
879 
880         Response response = service.getRoot();
881         assertEquals( 200, response.getStatus() );
882         String entity = entityAsString( response );
883         Map<String, Object> map = JsonHelper.jsonToMap( entity );
884         assertNotNull( map.get( "node" ) );
885 
886         assertNotNull( map.get( "node_index" ) );
887         assertNotNull( map.get( "extensions_info" ) );
888         assertNotNull( map.get( "relationship_index" ) );
889 
890         assertNull( map.get( "reference_node" ) );
891 
892         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
893     }
894 
895     @Test
896     public void shouldBeAbleToIndexNode() throws DatabaseBlockedException, JsonParseException
897     {
898         Response response = service.createNode( null );
899         URI nodeUri = (URI) response.getMetadata().getFirst( "Location" );
900 
901         String key = "key";
902         String value = "value";
903         response = service.addToNodeIndex( "node", key, value,
904                 JsonHelper.createJsonFrom( nodeUri.toString() ) );
905         assertEquals( 201, response.getStatus() );
906         assertNotNull( response.getMetadata().getFirst( "Location" ) );
907     }
908 
909     @Test
910     public void shouldBeAbleToGetNodeRepresentationFromIndexUri() throws DatabaseBlockedException, JsonParseException
911     {
912         String key = "key_get_noderep";
913         String value = "value";
914         long nodeId = helper.createNode();
915         String indexName = "all-the-best-nodes";
916         helper.addNodeToIndex( indexName, key, value, nodeId );
917         Response response = service.getNodeFromIndexUri( indexName, key, value, nodeId );
918         assertEquals( 200, response.getStatus() );
919         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
920         assertNull( response.getMetadata().get( "Location" ) );
921         Map<String, Object> map = JsonHelper.jsonToMap( entityAsString( response ) );
922         assertNotNull( map );
923         assertTrue( map.containsKey( "self" ) );
924     }
925 
926     @Test
927     public void shouldBeAbleToGetRelationshipRepresentationFromIndexUri() throws DatabaseBlockedException, JsonParseException
928     {
929         String key = "key_get_noderep";
930         String value = "value";
931         long startNodeId = helper.createNode();
932         long endNodeId = helper.createNode();
933         String relationshipType = "knows";
934         long relationshipId = helper.createRelationship( relationshipType, startNodeId, endNodeId );
935 
936         String indexName = "all-the-best-relationships";
937         helper.addRelationshipToIndex( indexName, key, value, relationshipId );
938         Response response = service.getRelationshipFromIndexUri( indexName, key, value, relationshipId );
939         assertEquals( 200, response.getStatus() );
940         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
941         assertNull( response.getMetadata().get( "Location" ) );
942         Map<String, Object> map = JsonHelper.jsonToMap( entityAsString( response ) );
943         assertNotNull( map );
944         assertTrue( map.containsKey( "self" ) );
945     }
946 
947 
948     @Test
949     public void shouldBeAbleToGetListOfNodeRepresentationsFromIndexLookup() throws DatabaseBlockedException, PropertyValueException, URISyntaxException
950     {
951         RestfulModelHelper.DomainModel matrixers = RestfulModelHelper.generateMatrix( service );
952 
953         Map.Entry<String, String> indexedKeyValue = matrixers.indexedNodeKeyValues.entrySet().iterator().next();
954         Response response = service.getIndexedNodes( matrixers.nodeIndexName, indexedKeyValue.getKey(), indexedKeyValue.getValue() );
955         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
956         Collection<?> items = (Collection<?>) JsonHelper.jsonToSingleValue( entityAsString( response ) );
957         int counter = 0;
958         for ( Object item : items )
959         {
960             Map<?, ?> map = (Map<?, ?>) item;
961             Map<?, ?> properties = (Map<?, ?>) map.get( "data" );
962             assertNotNull( map.get( "self" ) );
963             String indexedUri = (String) map.get( "indexed" );
964             assertEquals( matrixers.indexedNodeUriToEntityMap.get( new URI(indexedUri) ).properties.get("name"), properties.get( "name" ) );
965             counter++;
966         }
967         assertEquals( 2, counter );
968     }
969 
970     @Test
971     public void shouldBeAbleToGetListOfNodeRepresentationsFromIndexQuery() throws DatabaseBlockedException, PropertyValueException, URISyntaxException
972     {
973         RestfulModelHelper.DomainModel matrixers = RestfulModelHelper.generateMatrix( service );
974 
975         Map.Entry<String, String> indexedKeyValue = matrixers.indexedNodeKeyValues.entrySet().iterator().next();
976         // query for the first letter with which the nodes were indexed.
977         Response response = service.getIndexedNodesByQuery( matrixers.nodeIndexName, indexedKeyValue.getKey(), indexedKeyValue.getValue().substring( 0, 1 ) + "*" );
978         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
979         Collection<?> items = (Collection<?>) JsonHelper.jsonToSingleValue( entityAsString( response ) );
980         int counter = 0;
981         for ( Object item : items )
982         {
983             Map<?, ?> map = (Map<?, ?>) item;
984             Map<?, ?> properties = (Map<?, ?>) map.get( "data" );
985             String indexedUri = (String) map.get( "indexed" ); // unlike exact match, a query can not return a sensible index uri for the result
986             assertNull(indexedUri);
987             String selfUri = (String) map.get("self");
988             assertNotNull( selfUri );
989             assertEquals( matrixers.nodeUriToEntityMap.get( new URI(selfUri) ).properties.get("name"), properties.get( "name" ) );
990             counter++;
991         }
992         assertThat( counter, is( greaterThanOrEqualTo(2)) );
993     }
994 
995 
996     @Test
997     public void shouldBeAbleToGetListOfRelationshipRepresentationsFromIndexLookup() throws DatabaseBlockedException, PropertyValueException
998     {
999         String key = "key_get";
1000         String value = "value";
1001 
1002         long startNodeId = helper.createNode();
1003         long endNodeId = helper.createNode();
1004 
1005         String relationshipType1 = "KNOWS";
1006         long relationshipId1 = helper.createRelationship( relationshipType1, startNodeId, endNodeId );
1007         String relationshipType2 = "PLAYS-NICE-WITH";
1008         long relationshipId2 = helper.createRelationship( relationshipType2, startNodeId, endNodeId );
1009 
1010         String indexName = "matrixal-relationships";
1011         helper.createRelationshipIndex( indexName );
1012         helper.addRelationshipToIndex( indexName, key, value, relationshipId1 );
1013         helper.addRelationshipToIndex( indexName, key, value, relationshipId2 );
1014 
1015         Response response = service.getIndexedRelationships( indexName, key, value );
1016         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1017         Collection<?> items = (Collection<?>) JsonHelper.jsonToSingleValue( entityAsString( response ) );
1018         int counter = 0;
1019         for ( Object item : items )
1020         {
1021             Map<?, ?> map = (Map<?, ?>) item;
1022             assertNotNull( map.get( "self" ) );
1023             String indexedUri = (String) map.get( "indexed" );
1024             assertThat( indexedUri, containsString( key ) );
1025             assertThat( indexedUri, containsString( value ) );
1026             assertTrue( indexedUri.endsWith( Long.toString( relationshipId1 ) ) ||
1027                     indexedUri.endsWith( Long.toString( relationshipId2 ) ) );
1028             counter++;
1029         }
1030         assertEquals( 2, counter );
1031     }
1032 
1033     @Test
1034     public void shouldBeAbleToGetListOfRelationshipRepresentationsFromIndexQuery() throws DatabaseBlockedException, PropertyValueException
1035     {
1036         String key = "key_get";
1037         String value = "value";
1038 
1039         long startNodeId = helper.createNode();
1040         long endNodeId = helper.createNode();
1041 
1042         String relationshipType1 = "KNOWS";
1043         long relationshipId1 = helper.createRelationship( relationshipType1, startNodeId, endNodeId );
1044         String relationshipType2 = "PLAYS-NICE-WITH";
1045         long relationshipId2 = helper.createRelationship( relationshipType2, startNodeId, endNodeId );
1046 
1047         String indexName = "matrixal-relationships";
1048         helper.createRelationshipIndex( indexName );
1049         helper.addRelationshipToIndex( indexName, key, value, relationshipId1 );
1050         helper.addRelationshipToIndex( indexName, key, value, relationshipId2 );
1051 
1052         Response response = service.getIndexedRelationshipsByQuery( indexName, key, value.substring( 0,1 ) + "*" );
1053         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1054         Collection<?> items = (Collection<?>) JsonHelper.jsonToSingleValue( entityAsString( response ) );
1055         int counter = 0;
1056         for ( Object item : items )
1057         {
1058             Map<?, ?> map = (Map<?, ?>) item;
1059             String indexedUri = (String) map.get( "indexed" );
1060             assertNull( indexedUri ); // queries can not return a sensible index uri
1061             String selfUri = (String) map.get("self");
1062             assertNotNull( selfUri );
1063             assertTrue( selfUri.endsWith( Long.toString( relationshipId1 ) ) ||
1064                     selfUri.endsWith( Long.toString( relationshipId2 ) ) );
1065             counter++;
1066         }
1067         assertThat( counter, is(greaterThanOrEqualTo( 2 )));
1068     }
1069 
1070     @Test
1071     public void shouldGet200AndEmptyListWhenNothingFoundInIndexLookup() throws DatabaseBlockedException, PropertyValueException
1072     {
1073         String indexName = "nothing-in-this-index";
1074         helper.createNodeIndex( indexName );
1075         Response response = service.getIndexedNodes( indexName, "fooo", "baaar" );
1076         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1077         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
1078         String entity = entityAsString( response );
1079         Object parsedJson = JsonHelper.jsonToSingleValue( entity );
1080         assertTrue( parsedJson instanceof Collection<?> );
1081         assertTrue( ((Collection<?>) parsedJson).isEmpty() );
1082     }
1083 
1084     @Test
1085     public void shouldBeAbleToRemoveNodeFromIndex() throws DatabaseBlockedException
1086     {
1087         long nodeId = helper.createNode();
1088         String key = "key_remove";
1089         String value = "value";
1090         helper.addNodeToIndex( "node", key, value, nodeId );
1091         assertEquals( 1, helper.getIndexedNodes( "node", key, value ).size() );
1092         Response response = service.deleteFromNodeIndex( "node", key, value, nodeId );
1093         assertEquals( Status.NO_CONTENT.getStatusCode(), response.getStatus() );
1094         assertEquals( 0, helper.getIndexedNodes( "node", key, value ).size() );
1095     }
1096 
1097     @Test
1098     public void shouldBeAbleToRemoveRelationshipFromIndex() throws DatabaseBlockedException
1099     {
1100         long startNodeId = helper.createNode();
1101         long endNodeId = helper.createNode();
1102         String relationshipType = "related-to";
1103         long relationshipId = helper.createRelationship( relationshipType, startNodeId, endNodeId );
1104         String key = "key_remove";
1105         String value = "value";
1106         String indexName = "relationships";
1107         helper.addRelationshipToIndex( indexName, key, value, relationshipId );
1108         assertEquals( 1, helper.getIndexedRelationships( indexName, key, value ).size() );
1109         Response response = service.deleteFromRelationshipIndex( indexName, key, value, relationshipId );
1110         assertEquals( Status.NO_CONTENT.getStatusCode(), response.getStatus() );
1111         assertEquals( 0, helper.getIndexedRelationships( indexName, key, value ).size() );
1112     }
1113 
1114     @Test
1115     public void shouldGet404IfRemovingNonExistentNodeIndexing() throws DatabaseBlockedException
1116     {
1117         Response response = service.deleteFromNodeIndex( "nodes", "bogus", "bogus", 999999 );
1118         assertEquals( Status.NOT_FOUND.getStatusCode(), response.getStatus() );
1119     }
1120 
1121     @Test
1122     public void shouldGet404IfRemovingNonExistentRelationshipIndexing() throws DatabaseBlockedException
1123     {
1124         Response response = service.deleteFromRelationshipIndex( "relationships", "bogus", "bogus", 999999 );
1125         assertEquals( Status.NOT_FOUND.getStatusCode(), response.getStatus() );
1126     }
1127 
1128     @Test
1129     public void shouldGet404WhenTraversingFromNonExistentNode() throws DatabaseBlockedException
1130     {
1131         Response response = service.traverse( 9999999, TraverserReturnType.node, "{}" );
1132         assertEquals( Status.NOT_FOUND.getStatusCode(), response.getStatus() );
1133     }
1134 
1135     @Test
1136     public void shouldGet200WhenNoHitsReturnedFromTraverse() throws DatabaseBlockedException, BadInputException
1137     {
1138         long startNode = helper.createNode();
1139         Response response = service.traverse( startNode, TraverserReturnType.node, "" );
1140         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1141 
1142         List<Object> resultAsList = output.getResultAsList();
1143 
1144         assertThat( resultAsList.size(), is( 0 ) );
1145     }
1146 
1147     @Test
1148     public void shouldGetSomeHitsWhenTraversingWithDefaultDescription() throws DatabaseBlockedException
1149     {
1150         long startNode = helper.createNode();
1151         long child1_l1 = helper.createNode();
1152         helper.createRelationship( "knows", startNode, child1_l1 );
1153         long child2_l1 = helper.createNode();
1154         helper.createRelationship( "knows", startNode, child2_l1 );
1155         long child1_l2 = helper.createNode();
1156         helper.createRelationship( "knows", child2_l1, child1_l2 );
1157         Response response = service.traverse( startNode, TraverserReturnType.node, "" );
1158         String entity = entityAsString( response );
1159         assertTrue( entity.contains( "/node/" + child1_l1 ) );
1160         assertTrue( entity.contains( "/node/" + child2_l1 ) );
1161         assertFalse( entity.contains( "/node/" + child1_l2 ) );
1162         assertEquals( response.getMetadata().getFirst( HttpHeaders.CONTENT_ENCODING ), "UTF-8" );
1163     }
1164 
1165     @Test
1166     public void shouldBeAbleToDescribeTraverser() throws DatabaseBlockedException
1167     {
1168         long startNode = helper.createNode( MapUtil.map( "name", "Mattias" ) );
1169         long node1 = helper.createNode( MapUtil.map( "name", "Emil" ) );
1170         long node2 = helper.createNode( MapUtil.map( "name", "Johan" ) );
1171         long node3 = helper.createNode( MapUtil.map( "name", "Tobias" ) );
1172         helper.createRelationship( "knows", startNode, node1 );
1173         helper.createRelationship( "knows", startNode, node2 );
1174         helper.createRelationship( "knows", node1, node3 );
1175         String description = "{" + "\"prune evaluator\":{\"language\":\"builtin\",\"name\":\"none\"},"
1176                 + "\"return filter\":{\"language\":\"javascript\",\"body\":\"position.endNode().getProperty('name').toLowerCase().contains('t');\"},"
1177                 + "\"order\":\"depth first\"," + "\"relationships\":{\"type\":\"knows\",\"direction\":\"all\"}" + "}";
1178         Response response = service.traverse( startNode, TraverserReturnType.node, description );
1179         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1180         String entity = entityAsString( response );
1181         assertTrue( entity.contains( "node/" + startNode ) );
1182         assertFalse( entity.contains( "node/" + node1 ) );
1183         assertFalse( entity.contains( "node/" + node2 ) );
1184         assertTrue( entity.contains( "node/" + node3 ) );
1185     }
1186 
1187     @Test
1188     public void shouldBeAbleToGetOtherResultTypesWhenTraversing() throws DatabaseBlockedException
1189     {
1190         long startNode = helper.createNode( MapUtil.map( "name", "Mattias" ) );
1191         long node1 = helper.createNode( MapUtil.map( "name", "Emil" ) );
1192         long node2 = helper.createNode( MapUtil.map( "name", "Johan" ) );
1193         long node3 = helper.createNode( MapUtil.map( "name", "Tobias" ) );
1194         long rel1 = helper.createRelationship( "knows", startNode, node1 );
1195         long rel2 = helper.createRelationship( "knows", startNode, node2 );
1196         long rel3 = helper.createRelationship( "knows", node1, node3 );
1197 
1198         Response response = service.traverse( startNode, TraverserReturnType.relationship, "" );
1199         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1200         String entity = entityAsString( response );
1201         assertTrue( entity.contains( "/relationship/" + rel1 ) );
1202         assertTrue( entity.contains( "/relationship/" + rel2 ) );
1203         assertFalse( entity.contains( "/relationship/" + rel3 ) );
1204 
1205         response = service.traverse( startNode, TraverserReturnType.path, "" );
1206         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1207         entity = entityAsString( response );
1208         assertTrue( entity.contains( "nodes" ) );
1209         assertTrue( entity.contains( "relationships" ) );
1210         assertTrue( entity.contains( "length" ) );
1211 
1212         response = service.traverse( startNode, TraverserReturnType.fullpath, "" );
1213         assertEquals( Status.OK.getStatusCode(), response.getStatus() );
1214         entity = entityAsString( response );
1215         assertTrue( entity.contains( "nodes" ) );
1216         assertTrue( entity.contains( "data" ) );
1217         assertTrue( entity.contains( "type" ) );
1218         assertTrue( entity.contains( "self" ) );
1219         assertTrue( entity.contains( "outgoing_relationships" ) );
1220         assertTrue( entity.contains( "incoming_relationships" ) );
1221         assertTrue( entity.contains( "relationships" ) );
1222         assertTrue( entity.contains( "length" ) );
1223     }
1224 
1225     private static String markWithUnicodeMarker( String string )
1226     {
1227         return String.valueOf( (char) 0xfeff ) + string;
1228     }
1229 
1230     @Test
1231     public void shouldBeAbleToFindSinglePathBetweenTwoNodes() throws Exception
1232     {
1233         long n1 = helper.createNode();
1234         long n2 = helper.createNode();
1235         helper.createRelationship( "knows", n1, n2 );
1236         Map<String, Object> config = MapUtil.map(
1237                 "max depth", 3,
1238                 "algorithm", "shortestPath",
1239                 "to", Long.toString( n2 ),
1240                 "relationships", MapUtil.map(
1241                 "type", "knows",
1242                 "direction", "out" ) );
1243 
1244         String payload = JsonHelper.createJsonFrom( config );
1245 
1246         Response response = service.singlePath( n1, payload );
1247         assertThat( response.getStatus(), is( 200 ) );
1248 
1249         Map<String, Object> resultAsMap = output.getResultAsMap();
1250         assertThat( (Integer) resultAsMap.get( "length" ), is( 1 ) );
1251     }
1252 
1253     @Test
1254     public void shouldBeAbleToFindSinglePathBetweenTwoNodesEvenWhenAskingForAllPaths() throws Exception
1255     {
1256         long n1 = helper.createNode();
1257         long n2 = helper.createNode();
1258         helper.createRelationship( "knows", n1, n2 );
1259         Map<String, Object> config = MapUtil.map(
1260                 "max depth", 3,
1261                 "algorithm", "shortestPath",
1262                 "to", Long.toString( n2 ),
1263                 "relationships", MapUtil.map(
1264                 "type", "knows",
1265                 "direction", "out" ) );
1266 
1267         String payload = JsonHelper.createJsonFrom( config );
1268 
1269         Response response = service.allPaths( n1, payload );
1270         assertThat( response.getStatus(), is( 200 ) );
1271 
1272         List<Object> resultAsList = output.getResultAsList();
1273         assertThat( resultAsList.size(), is( 1 ) );
1274     }
1275 
1276     @Test
1277     public void shouldBeAbleToParseJsonEvenWithUnicodeMarkerAtTheStart() throws DatabaseBlockedException, JsonParseException
1278     {
1279         Response response = service.createNode( markWithUnicodeMarker( "{\"name\":\"Mattias\"}" ) );
1280         assertEquals( Status.CREATED.getStatusCode(), response.getStatus() );
1281         String nodeLocation = response.getMetadata().getFirst( HttpHeaders.LOCATION ).toString();
1282 
1283         long node = helper.createNode();
1284         assertEquals( Status.NO_CONTENT.getStatusCode(), service.setNodeProperty( node, "foo",
1285                 markWithUnicodeMarker( "\"bar\"" ) ).getStatus() );
1286         assertEquals( Status.NO_CONTENT.getStatusCode(), service.setNodeProperty( node, "foo",
1287                 markWithUnicodeMarker( "" + 10 ) ).getStatus() );
1288         assertEquals( Status.NO_CONTENT.getStatusCode(), service.setAllNodeProperties( node,
1289                 markWithUnicodeMarker( "{\"name\":\"Something\",\"number\":10}" ) )
1290                 .getStatus() );
1291 
1292         assertEquals( Status.CREATED.getStatusCode(),
1293                 service.createRelationship(
1294                         node,
1295                         markWithUnicodeMarker( "{\"to\":\"" + nodeLocation + "\",\"type\":\"knows\"}" ) ).getStatus() );
1296 
1297         long relationship = helper.createRelationship( "knows" );
1298         assertEquals( Status.NO_CONTENT.getStatusCode(), service.setRelationshipProperty(
1299                 relationship, "foo", markWithUnicodeMarker( "\"bar\"" ) ).getStatus() );
1300         assertEquals( Status.NO_CONTENT.getStatusCode(), service.setRelationshipProperty(
1301                 relationship, "foo", markWithUnicodeMarker( "" + 10 ) ).getStatus() );
1302         assertEquals(
1303                 Status.NO_CONTENT.getStatusCode(),
1304                 service.setAllRelationshipProperties( relationship,
1305                         markWithUnicodeMarker( "{\"name\":\"Something\",\"number\":10}" ) ).getStatus() );
1306 
1307         assertEquals( Status.CREATED.getStatusCode(), service.addToNodeIndex( "node", "foo", "bar",
1308                 markWithUnicodeMarker( JsonHelper.createJsonFrom( nodeLocation ) ) ).getStatus() );
1309 
1310         assertEquals( Status.OK.getStatusCode(), service.traverse( node, TraverserReturnType.node,
1311                 markWithUnicodeMarker( "{\"max depth\":2}" ) ).getStatus() );
1312     }
1313 
1314     @Test
1315     public void shouldAdvertiseUriForQueringAllRelationsInTheDatabase() {
1316         Response response = service.getRoot();
1317         assertThat(new String((byte[])response.getEntity()), containsString("\"relationship_types\" : \"http://neo4j.org/relationship/types\""));
1318     }
1319 }