1   /**
2    * Licensed to Neo Technology under one or more contributor
3    * license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright
5    * ownership. Neo Technology licenses this file to you under
6    * the Apache License, Version 2.0 (the "License"); you may
7    * not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.neo4j.examples.socnet;
20  
21  import static org.hamcrest.CoreMatchers.equalTo;
22  import static org.hamcrest.collection.IsCollectionContaining.hasItems;
23  import static org.junit.Assert.assertThat;
24  
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.Iterator;
28  import java.util.Random;
29  
30  import org.hamcrest.CoreMatchers;
31  import org.junit.After;
32  import org.junit.Before;
33  import org.junit.Test;
34  import org.neo4j.graphdb.GraphDatabaseService;
35  import org.neo4j.graphdb.Node;
36  import org.neo4j.graphdb.index.Index;
37  import org.neo4j.helpers.collection.IteratorUtil;
38  import org.neo4j.kernel.EmbeddedGraphDatabase;
39  
40  public class SocnetTest
41  {
42      private static final Random r = new Random( System.currentTimeMillis() );
43      private GraphDatabaseService graphDb;
44      private Index<Node> index;
45      private PersonRepository personRepository;
46      private int nrOfPersons;
47  
48      @Before
49      public void setup() throws Exception
50      {
51          graphDb = new EmbeddedGraphDatabase( "target/socnetdb" );
52          index = graphDb.index().forNodes( "nodes" );
53          personRepository = new PersonRepository( graphDb, index );
54          deleteSocialGraph();
55  
56          nrOfPersons = 20;
57          createPersons();
58          setupFriendsBetweenPeople( 10 );
59      }
60  
61      @After
62      public void teardown()
63      {
64          try
65          {
66              deleteSocialGraph();
67          }
68          finally
69          {
70              graphDb.shutdown();
71          }
72      }
73  
74      @Test
75      public void addStatusAndRetrieveIt() throws Exception
76      {
77          Person person = getRandomPerson();
78          person.addStatus( "Testing!" );
79  
80          StatusUpdate update = person.getStatus().iterator().next();
81  
82          assertThat( update, CoreMatchers.<Object>notNullValue() );
83          assertThat( update.getStatusText(), equalTo( "Testing!" ) );
84          assertThat( update.getPerson(), equalTo( person ) );
85      }
86  
87      @Test
88      public void multipleStatusesComeOutInTheRightOrder() throws Exception
89      {
90          ArrayList<String> statuses = new ArrayList<String>();
91          statuses.add( "Test1" );
92          statuses.add( "Test2" );
93          statuses.add( "Test3" );
94  
95          Person person = getRandomPerson();
96          for ( String status : statuses )
97          {
98              person.addStatus( status );
99          }
100 
101         int i = statuses.size();
102         for ( StatusUpdate update : person.getStatus() )
103         {
104             i--;
105             assertThat( update.getStatusText(), equalTo( statuses.get( i ) ) );
106         }
107     }
108 
109     @Test
110     public void removingOneFriendIsHandledCleanly()
111     {
112         Person person1 = personRepository.getPersonByName( "person#1" );
113         Person person2 = personRepository.getPersonByName( "person#2" );
114         person1.addFriend( person2 );
115 
116         int noOfFriends = person1.getNrOfFriends();
117 
118         person1.removeFriend( person2 );
119 
120         int noOfFriendsAfterChange = person1.getNrOfFriends();
121 
122         assertThat( noOfFriends, equalTo( noOfFriendsAfterChange + 1 ) );
123     }
124 
125     @Test
126     public void retrieveStatusUpdatesInDateOrder() throws Exception
127     {
128         Person person = getRandomPersonWithFriends();
129         int numberOfStatuses = 20;
130 
131         for ( int i = 0; i < numberOfStatuses; i++ )
132         {
133             Person friend = getRandomFriendOf( person );
134             friend.addStatus( "Dum-deli-dum..." );
135         }
136 
137         ArrayList<StatusUpdate> updates = fromIterableToArrayList( person.friendStatuses() );
138         assertThat( updates.size(), equalTo( numberOfStatuses ) );
139         assertUpdatesAreSortedByDate( updates );
140     }
141 
142     @Test
143     public void friendsOfFriendsWorks() throws Exception
144     {
145         Person person = getRandomPerson();
146         Person friend = getRandomFriendOf( person );
147 
148         for ( Person friendOfFriend : friend.getFriends() )
149         {
150             if ( !friendOfFriend.equals( person ) )
151             { // You can't be friends with yourself.
152                 assertThat( person.getFriendsOfFriends(), hasItems( friendOfFriend ) );
153             }
154         }
155     }
156 
157     @Test
158     public void shouldReturnTheCorrectPersonFromAnyStatusUpdate() throws Exception
159     {
160         Person person = getRandomPerson();
161         person.addStatus( "Foo" );
162         person.addStatus( "Bar" );
163         person.addStatus( "Baz" );
164 
165         for(StatusUpdate status : person.getStatus())
166         {
167             assertThat(status.getPerson(), equalTo( person ));
168         }
169     }
170 
171     @Test
172     public void getPathBetweenFriends() throws Exception
173     {
174         deleteSocialGraph();
175         Person start = personRepository.createPerson( "start" );
176         Person middleMan1 = personRepository.createPerson( "middle1" );
177         Person middleMan2 = personRepository.createPerson( "middle2" );
178         Person endMan = personRepository.createPerson( "endMan" );
179 
180         // Start -> middleMan1 -> middleMan2 -> endMan
181 
182         start.addFriend( middleMan1 );
183         middleMan1.addFriend( middleMan2 );
184         middleMan2.addFriend( endMan );
185 
186         Iterable<Person> path = start.getShortestPathTo( endMan, 4 );
187 
188         assertPathIs( path, start, middleMan1, middleMan2, endMan );
189         //assertThat( path, matchesPathByProperty(Person.NAME, "start", "middle1", "middle2", "endMan"));
190     }
191 
192     @Test
193     public void singleFriendRecommendation() throws Exception
194     {
195         deleteSocialGraph();
196         Person a = personRepository.createPerson( "a" );
197         Person b = personRepository.createPerson( "b" );
198         Person c = personRepository.createPerson( "c" );
199         Person d = personRepository.createPerson( "d" );
200         Person e = personRepository.createPerson( "e" );
201 
202         // A is friends with B,C and D
203         a.addFriend( b );
204         a.addFriend( c );
205         a.addFriend( d );
206 
207         // E is also friend with B, C and D
208         e.addFriend( b );
209         e.addFriend( c );
210         e.addFriend( d );
211 
212         Person recommendation = IteratorUtil.single( a.getFriendRecommendation( 1 ).iterator() );
213 
214         assertThat( recommendation, equalTo( e ) );
215     }
216 
217     @Test
218     public void weightedFriendRecommendation() throws Exception
219     {
220         deleteSocialGraph();
221         Person a = personRepository.createPerson( "a" );
222         Person b = personRepository.createPerson( "b" );
223         Person c = personRepository.createPerson( "c" );
224         Person d = personRepository.createPerson( "d" );
225         Person e = personRepository.createPerson( "e" );
226         Person f = personRepository.createPerson( "f" );
227 
228 
229         // A is friends with B,C and D
230         a.addFriend( b );
231         a.addFriend( c );
232         a.addFriend( d );
233 
234         // E is only friend with B
235         e.addFriend( b );
236 
237         // F is friend with B, C, D
238         f.addFriend( b );
239         f.addFriend( c );
240         f.addFriend( d );
241 
242         ArrayList<Person> recommendations = fromIterableToArrayList( a.getFriendRecommendation( 2 ).iterator() );
243 
244         assertThat( recommendations.get( 0 ), equalTo( f ));
245         assertThat( recommendations.get( 1 ), equalTo( e ));
246     }
247 
248     private <T> ArrayList<T> fromIterableToArrayList( Iterator<T> iterable )
249     {
250         ArrayList<T> collection = new ArrayList<T>();
251         IteratorUtil.addToCollection( iterable, collection );
252         return collection;
253     }
254 
255     private void assertPathIs( Iterable<Person> path,
256                                        Person... expectedPath )
257     {
258         ArrayList<Person> pathArray = new ArrayList<Person>();
259         IteratorUtil.addToCollection( path, pathArray );
260         assertThat( pathArray.size(), equalTo( expectedPath.length ) );
261         for ( int i = 0; i < expectedPath.length; i++ )
262         {
263             assertThat( pathArray.get( i ), equalTo( expectedPath[ i ] ) );
264         }
265     }
266 
267     private void setupFriendsBetweenPeople( int maxNrOfFriendsEach )
268     {
269         for ( Person person : personRepository.getAllPersons() )
270         {
271             int nrOfFriends = r.nextInt( maxNrOfFriendsEach ) + 1;
272             for ( int j = 0; j < nrOfFriends; j++ )
273             {
274                 person.addFriend( getRandomPerson() );
275             }
276         }
277     }
278 
279     private Person getRandomPerson()
280     {
281         return personRepository.getPersonByName( "person#"
282                 + r.nextInt( nrOfPersons ) );
283     }
284 
285     private void deleteSocialGraph()
286     {
287         for ( Person person : personRepository.getAllPersons() )
288         {
289             personRepository.deletePerson( person );
290         }
291     }
292 
293     private Person getRandomFriendOf( Person p )
294     {
295         ArrayList<Person> friends = new ArrayList<Person>();
296         IteratorUtil.addToCollection( p.getFriends().iterator(), friends );
297         return friends.get( r.nextInt( friends.size() ) );
298     }
299 
300     private Person getRandomPersonWithFriends()
301     {
302         Person p;
303         do
304         {
305             p = getRandomPerson();
306         }
307         while ( p.getNrOfFriends() == 0 );
308         return p;
309     }
310 
311     private void createPersons() throws Exception
312     {
313         for ( int i = 0; i < nrOfPersons; i++ )
314         {
315             personRepository.createPerson( "person#" + i );
316         }
317     }
318 
319     private void assertUpdatesAreSortedByDate(
320             ArrayList<StatusUpdate> statusUpdates )
321     {
322         Date date = new Date( 0 );
323         for ( StatusUpdate update : statusUpdates )
324         {
325             org.junit.Assert.assertTrue( date.getTime() < update.getDate().getTime() );
326             // TODO: Should be assertThat(date, lessThan(update.getDate));
327         }
328     }
329 }