    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 }