View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  The ASF licenses this file to You
4    * under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.  For additional information regarding
15   * copyright in this work, please see the NOTICE file in the top level
16   * directory of this distribution.
17   */
18  package org.apache.shindig.social.dataservice.integration;
19  
20  import org.apache.shindig.social.core.model.AddressImpl;
21  import org.apache.shindig.social.core.model.BodyTypeImpl;
22  import org.apache.shindig.social.core.model.EnumImpl;
23  import org.apache.shindig.social.core.model.ListFieldImpl;
24  import org.apache.shindig.social.core.model.NameImpl;
25  import org.apache.shindig.social.core.model.OrganizationImpl;
26  import org.apache.shindig.social.core.model.PersonImpl;
27  import org.apache.shindig.social.core.model.UrlImpl;
28  import org.apache.shindig.social.opensocial.model.Address;
29  import org.apache.shindig.social.opensocial.model.BodyType;
30  import org.apache.shindig.social.opensocial.model.Enum;
31  import org.apache.shindig.social.opensocial.model.ListField;
32  import org.apache.shindig.social.opensocial.model.Name;
33  import org.apache.shindig.social.opensocial.model.Organization;
34  import org.apache.shindig.social.opensocial.model.Person;
35  import org.apache.shindig.social.opensocial.model.Url;
36  import org.apache.shindig.social.opensocial.util.XSDValidator;
37  
38  import com.google.common.collect.Lists;
39  import com.google.common.collect.Maps;
40  import org.junit.Test;
41  import org.w3c.dom.Node;
42  import org.w3c.dom.NodeList;
43  import org.xml.sax.InputSource;
44  
45  import java.io.StringReader;
46  import java.util.Date;
47  import java.util.List;
48  import java.util.Map;
49  
50  import javax.xml.xpath.XPath;
51  import javax.xml.xpath.XPathConstants;
52  import javax.xml.xpath.XPathFactory;
53  
54  public class RestfulXmlPeopleTest extends AbstractLargeRestfulTests {
55    private Person canonical;
56    private XPathFactory xpathFactory;
57  
58    protected void setUp() throws Exception {
59      super.setUp();
60      xpathFactory = XPathFactory.newInstance();
61  
62      NameImpl name = new NameImpl("Sir Shin H. Digg Social Butterfly");
63      name.setAdditionalName("H");
64      name.setFamilyName("Digg");
65      name.setGivenName("Shin");
66      name.setHonorificPrefix("Sir");
67      name.setHonorificSuffix("Social Butterfly");
68      canonical = new PersonImpl("canonical", "Shin Digg", name);
69  
70      canonical.setAboutMe("I have an example of every piece of data");
71      canonical.setActivities(Lists.newArrayList("Coding Shindig"));
72  
73      Address address = new AddressImpl(
74          "PoBox 3565, 1 OpenStandards Way, Apache, CA");
75      address.setCountry("US");
76      address.setLatitude(28.3043F);
77      address.setLongitude(143.0859F);
78      address.setLocality("who knows");
79      address.setPostalCode("12345");
80      address.setRegion("Apache, CA");
81      address.setStreetAddress("1 OpenStandards Way");
82      address.setType("home");
83      address.setFormatted("PoBox 3565, 1 OpenStandards Way, Apache, CA");
84      canonical.setAddresses(Lists.newArrayList(address));
85  
86      canonical.setAge(33);
87      BodyTypeImpl bodyType = new BodyTypeImpl();
88      bodyType.setBuild("svelte");
89      bodyType.setEyeColor("blue");
90      bodyType.setHairColor("black");
91      bodyType.setHeight(1.84F); // meters as per spec
92      bodyType.setWeight(74F); // kg as per spec
93      canonical.setBodyType(bodyType);
94  
95      canonical.setBooks(Lists.newArrayList("The Cathedral & the Bazaar",
96          "Catch 22"));
97      canonical.setCars(Lists.newArrayList("beetle", "prius"));
98      canonical.setChildren("3");
99      AddressImpl location = new AddressImpl();
100     location.setLatitude(48.858193F);
101     location.setLongitude(2.29419F);
102     canonical.setCurrentLocation(location);
103 
104     canonical.setBirthday(new Date());
105     canonical.setDrinker(new EnumImpl<Enum.Drinker>(Enum.Drinker.SOCIALLY));
106     ListField email = new ListFieldImpl("work",
107         "shindig-dev@incubator.apache.org");
108     canonical.setEmails(Lists.newArrayList(email));
109 
110     canonical.setEthnicity("developer");
111     canonical.setFashion("t-shirts");
112     canonical.setFood(Lists.newArrayList("sushi", "burgers"));
113     canonical.setGender(Person.Gender.male);
114     canonical.setHappiestWhen("coding");
115     canonical.setHasApp(true);
116     canonical
117         .setHeroes(Lists.newArrayList("Doug Crockford", "Charles Babbage"));
118     canonical.setHumor("none to speak of");
119     canonical.setInterests(Lists.newArrayList("PHP", "Java"));
120     canonical.setJobInterests("will work for beer");
121 
122     Organization job1 = new OrganizationImpl();
123     job1.setAddress(new AddressImpl("1 Shindig Drive"));
124     job1.setDescription("lots of coding");
125     job1.setEndDate(new Date());
126     job1.setField("Software Engineering");
127     job1.setName("Apache.com");
128     job1.setSalary("$1000000000");
129     job1.setStartDate(new Date());
130     job1.setSubField("Development");
131     job1.setTitle("Grand PooBah");
132     job1.setWebpage("http://incubator.apache.org/projects/shindig.html");
133     job1.setType("job");
134 
135     Organization job2 = new OrganizationImpl();
136     job2.setAddress(new AddressImpl("1 Skid Row"));
137     job2.setDescription("");
138     job2.setEndDate(new Date());
139     job2.setField("College");
140     job2.setName("School of hard Knocks");
141     job2.setSalary("$100");
142     job2.setStartDate(new Date());
143     job2.setSubField("Lab Tech");
144     job2.setTitle("Gopher");
145     job2.setWebpage("");
146     job2.setType("job");
147 
148     canonical.setOrganizations(Lists.newArrayList(job1, job2));
149 
150     canonical.setUpdated(new Date());
151     canonical.setLanguagesSpoken(Lists.newArrayList("English", "Dutch",
152         "Esperanto"));
153     canonical.setLivingArrangement("in a house");
154     Enum<Enum.LookingFor> lookingForRandom = new EnumImpl<Enum.LookingFor>(
155         Enum.LookingFor.RANDOM, "Random");
156     Enum<Enum.LookingFor> lookingForNetworking = new EnumImpl<Enum.LookingFor>(
157         Enum.LookingFor.NETWORKING, "Networking");
158     canonical.setLookingFor(Lists.newArrayList(lookingForRandom,
159         lookingForNetworking));
160     canonical.setMovies(Lists.newArrayList("Iron Man", "Nosferatu"));
161     canonical.setMusic(Lists.newArrayList("Chieftains", "Beck"));
162     canonical.setNetworkPresence(new EnumImpl<Enum.NetworkPresence>(
163         Enum.NetworkPresence.ONLINE));
164     canonical.setNickname("diggy");
165     canonical.setPets("dog,cat");
166     canonical.setPhoneNumbers(Lists.<ListField> newArrayList(new ListFieldImpl(
167         "work", "111-111-111"), new ListFieldImpl("mobile", "999-999-999")));
168 
169     canonical.setPoliticalViews("open leaning");
170     canonical.setProfileSong(new UrlImpl(
171         "http://www.example.org/songs/OnlyTheLonely.mp3", "Feelin' blue",
172         "road"));
173     canonical.setProfileVideo(new UrlImpl(
174         "http://www.example.org/videos/Thriller.flv", "Thriller", "video"));
175 
176     canonical.setQuotes(Lists.newArrayList("I am therfore I code", "Doh!"));
177     canonical.setRelationshipStatus("married to my job");
178     canonical.setReligion("druidic");
179     canonical.setRomance("twice a year");
180     canonical.setScaredOf("COBOL");
181     canonical.setSexualOrientation("north");
182     canonical.setSmoker(new EnumImpl<Enum.Smoker>(Enum.Smoker.NO));
183     canonical.setSports(Lists.newArrayList("frisbee", "rugby"));
184     canonical.setStatus("happy");
185     canonical.setTags(Lists.newArrayList("C#", "JSON", "template"));
186     canonical.setThumbnailUrl("http://www.example.org/pic/?id=1");
187     canonical.setUtcOffset(-8L);
188     canonical.setTurnOffs(Lists.newArrayList("lack of unit tests", "cabbage"));
189     canonical.setTurnOns(Lists.newArrayList("well document code"));
190     canonical.setTvShows(Lists.newArrayList("House", "Battlestar Galactica"));
191 
192     canonical
193         .setUrls(Lists.<Url> newArrayList(new UrlImpl(
194             "http://www.example.org/?id=1", "my profile", "Profile"),
195             new UrlImpl("http://www.example.org/pic/?id=1",
196                 "my awesome picture", "Thumbnail")));
197 
198   }
199 
200   /***
201    * Expected response for john.doe's json:
202    *
203    * { 'entry' :
204    * { 'id' : 'john.doe',
205    * 'name' : {'unstructured' : 'John Doe'},
206    * 'phoneNumbers' : [ { 'number' : '+33H000000000', 'type' : 'home'}, ],
207    * 'addresses' : [ {'formattedAddress' : 'My home address'} ],
208    * 'emails' : [
209    *    { 'value' : 'john.doe@work.bar', 'type' : 'work'}, ]
210    *
211    * ... etc, etc for all fields in the person object } } TODO: Finish up this
212    * test and make refactor so that it is easier to read
213    *
214    * @throws Exception
215    *           if test encounters an error
216    */
217   @Test
218   public void testGetPersonJson() throws Exception {
219     // TODO(doll): Test all of the date fields
220 
221     Map<String, String> extraParams = Maps.newHashMap();
222     String allFieldsParam = "";
223     for (String allField : Person.Field.ALL_FIELDS) {
224       allFieldsParam += allField + ",";
225     }
226     extraParams.put("fields", allFieldsParam);
227 
228     // Currently, for Shindig {pid}/@all/{uid} == {uid}/@self
229     String resp = getResponse("/people/canonical/@self", "GET", extraParams,
230         "xml", "application/xml");
231     
232     XSDValidator.validate(resp, XMLSCHEMA, XSDRESOURCE,false);
233     
234     XPath xp = xpathFactory.newXPath();
235     NodeList resultNodeList = (NodeList) xp.evaluate("/response/person",
236         new InputSource(new StringReader(resp)), XPathConstants.NODESET);
237     assertEquals(1, resultNodeList.getLength());
238 
239     Node personNode = resultNodeList.item(0);
240 
241     Map<String, List<Node>> childNodeMap = childNodesToNodeMap(personNode);
242     Map<String, List<String>> result = childNodesToMap(personNode);
243 
244     assertStringField(result, canonical.getAboutMe(), Person.Field.ABOUT_ME);
245     assertStringListField(result, canonical.getActivities(),
246         Person.Field.ACTIVITIES);
247 
248     List<Node> addressNodes = childNodeMap.get(Person.Field.ADDRESSES
249         .toString());
250     assertEquals(addressNodes.size(), canonical.getAddresses().size());
251     for (int i = 0; i < addressNodes.size(); i++) {
252       assertAddressField(canonical.getAddresses().get(i),
253           childNodesToMap(addressNodes.get(i)));
254     }
255 
256     assertEquals(canonical.getAge().intValue(), Integer.parseInt(result.get(
257         Person.Field.AGE.toString()).get(0)));
258 
259     Map<String, List<String>> bodyMap = childNodesToMap(childNodeMap.get(
260         Person.Field.BODY_TYPE.toString()).get(0));
261     BodyType body = canonical.getBodyType();
262 
263     assertStringField(bodyMap, body.getBuild(), BodyType.Field.BUILD);
264     assertStringField(bodyMap, body.getEyeColor(), BodyType.Field.EYE_COLOR);
265     assertStringField(bodyMap, body.getHairColor(), BodyType.Field.HAIR_COLOR);
266     assertFloatField(bodyMap, body.getHeight(), BodyType.Field.HEIGHT);
267     assertFloatField(bodyMap, body.getWeight(), BodyType.Field.WEIGHT);
268 
269     assertStringListField(result, canonical.getBooks(), Person.Field.BOOKS);
270     assertStringListField(result, canonical.getCars(), Person.Field.CARS);
271     assertStringField(result, canonical.getChildren(), Person.Field.CHILDREN);
272 
273     Map<String, List<String>> currentLocation = childNodesToMap(childNodeMap
274         .get(Person.Field.CURRENT_LOCATION.toString()).get(0));
275     assertFloatField(currentLocation, canonical.getCurrentLocation()
276         .getLatitude(), Address.Field.LATITUDE);
277     assertFloatField(currentLocation, canonical.getCurrentLocation()
278         .getLongitude(), Address.Field.LONGITUDE);
279 
280     assertStringField(result, canonical.getDisplayName(),
281         Person.Field.DISPLAY_NAME);
282 
283     // assertLongField(result, canonical.getBirthday().getTime(),
284     // Person.Field.BIRTHDAY);
285     // assertEnumField(result, canonical.getDrinker(), Person.Field.DRINKER);
286 
287     List<Node> emailArray = childNodeMap.get(Person.Field.EMAILS.toString());
288     assertEquals(1, emailArray.size());
289 
290     for (int i = 0; i < canonical.getEmails().size(); i++) {
291       ListField expectedEmail = canonical.getEmails().get(i);
292       Map<String, List<String>> actualEmail = childNodesToMap(emailArray.get(i));
293 
294       assertStringField(actualEmail, expectedEmail.getType(),
295           ListField.Field.TYPE);
296       assertStringField(actualEmail, expectedEmail.getValue(),
297           ListField.Field.VALUE);
298     }
299 
300     assertStringField(result, canonical.getEthnicity(), Person.Field.ETHNICITY);
301     assertStringField(result, canonical.getFashion(), Person.Field.FASHION);
302     assertStringListField(result, canonical.getFood(), Person.Field.FOOD);
303     assertStringField(result, canonical.getGender().toString(),
304         Person.Field.GENDER);
305     assertStringField(result, canonical.getHappiestWhen(),
306         Person.Field.HAPPIEST_WHEN);
307     assertBooleanField(result, canonical.getHasApp(), Person.Field.HAS_APP);
308     assertStringListField(result, canonical.getHeroes(), Person.Field.HEROES);
309     assertStringField(result, canonical.getHumor(), Person.Field.HUMOR);
310     assertStringField(result, canonical.getId(), Person.Field.ID);
311     assertStringListField(result, canonical.getInterests(),
312         Person.Field.INTERESTS);
313     assertStringField(result, canonical.getJobInterests(),
314         Person.Field.JOB_INTERESTS);
315 
316     assertOrganizationField(canonical.getOrganizations().get(0), childNodeMap
317         .get(Person.Field.ORGANIZATIONS.toString()).get(0));
318 
319     assertStringListField(result, canonical.getLanguagesSpoken(),
320         Person.Field.LANGUAGES_SPOKEN);
321     // assertDateField(result, canonical.getUpdated(),
322     // Person.Field.LAST_UPDATED);
323     assertStringField(result, canonical.getLivingArrangement(),
324         Person.Field.LIVING_ARRANGEMENT);
325     assertListEnumField(childNodeMap, canonical.getLookingFor(),
326         Person.Field.LOOKING_FOR);
327     assertStringListField(result, canonical.getMovies(), Person.Field.MOVIES);
328     assertStringListField(result, canonical.getMusic(), Person.Field.MUSIC);
329 
330     assertEquals(canonical.getName().getUnstructured(), childNodesToMap(
331         childNodeMap.get(Person.Field.NAME.toString()).get(0)).get(
332         Name.Field.UNSTRUCTURED.toString()).get(0));
333 
334     assertEnumField(childNodeMap, canonical.getNetworkPresence(),
335         Person.Field.NETWORKPRESENCE);
336     assertStringField(result, canonical.getNickname(), Person.Field.NICKNAME);
337     assertStringField(result, canonical.getPets(), Person.Field.PETS);
338 
339     List<Node> phoneArray = childNodeMap.get(Person.Field.PHONE_NUMBERS
340         .toString());
341     assertEquals(canonical.getPhoneNumbers().size(), phoneArray.size());
342 
343     for (int i = 0; i < canonical.getPhoneNumbers().size(); i++) {
344       ListField expectedPhone = canonical.getPhoneNumbers().get(i);
345       Map<String, List<String>> actualPhone = childNodesToMap(phoneArray.get(i));
346       assertEquals(expectedPhone.getType(), actualPhone.get(
347           ListField.Field.TYPE.toString()).get(0));
348       assertEquals(expectedPhone.getValue(), actualPhone.get(
349           ListField.Field.VALUE.toString()).get(0));
350     }
351 
352     assertStringField(result, canonical.getPoliticalViews(),
353         Person.Field.POLITICAL_VIEWS);
354 
355     assertUrlField(canonical.getProfileSong(), childNodesToMap(childNodeMap
356         .get(Person.Field.PROFILE_SONG.toString()).get(0)));
357     assertStringField(result, canonical.getProfileUrl(),
358         Person.Field.PROFILE_URL);
359     assertUrlField(canonical.getProfileVideo(), childNodesToMap(childNodeMap
360         .get(Person.Field.PROFILE_VIDEO.toString()).get(0)));
361 
362     assertStringListField(result, canonical.getQuotes(), Person.Field.QUOTES);
363     assertStringField(result, canonical.getRelationshipStatus(),
364         Person.Field.RELATIONSHIP_STATUS);
365     assertStringField(result, canonical.getReligion(), Person.Field.RELIGION);
366     assertStringField(result, canonical.getRomance(), Person.Field.ROMANCE);
367     assertStringField(result, canonical.getScaredOf(), Person.Field.SCARED_OF);
368 
369     assertStringField(result, canonical.getSexualOrientation(),
370         Person.Field.SEXUAL_ORIENTATION);
371     assertEnumField(childNodeMap, canonical.getSmoker(), Person.Field.SMOKER);
372     assertStringListField(result, canonical.getSports(), Person.Field.SPORTS);
373     assertStringField(result, canonical.getStatus(), Person.Field.STATUS);
374     assertStringListField(result, canonical.getTags(), Person.Field.TAGS);
375     assertStringField(result, canonical.getThumbnailUrl(),
376         Person.Field.THUMBNAIL_URL);
377     // TODO: time zone
378     assertStringListField(result, canonical.getTurnOffs(),
379         Person.Field.TURN_OFFS);
380     assertStringListField(result, canonical.getTurnOns(), Person.Field.TURN_ONS);
381     assertStringListField(result, canonical.getTvShows(), Person.Field.TV_SHOWS);
382   }
383 
384   private void assertAddressField(Address expected,
385       Map<String, List<String>> actual) {
386     assertStringField(actual, expected.getCountry(), Address.Field.COUNTRY);
387     assertFloatField(actual, expected.getLatitude(), Address.Field.LATITUDE);
388     assertStringField(actual, expected.getLocality(), Address.Field.LOCALITY);
389     assertFloatField(actual, expected.getLongitude(), Address.Field.LONGITUDE);
390     assertStringField(actual, expected.getPostalCode(),
391         Address.Field.POSTAL_CODE);
392     assertStringField(actual, expected.getRegion(), Address.Field.REGION);
393     assertStringField(actual, expected.getStreetAddress(),
394         Address.Field.STREET_ADDRESS);
395     assertStringField(actual, expected.getType(), Address.Field.TYPE);
396     assertStringField(actual, expected.getFormatted(), Address.Field.FORMATTED);
397   }
398 
399   private void assertUrlField(Url expected, Map<String, List<String>> actual) {
400     assertStringField(actual, expected.getValue(), Url.Field.VALUE);
401     assertStringField(actual, expected.getLinkText(), Url.Field.LINK_TEXT);
402     assertStringField(actual, expected.getType(), Url.Field.TYPE);
403   }
404 
405   private void assertOrganizationField(Organization expected, Node orgNode) {
406     Map<String, List<String>> actual = childNodesToMap(orgNode);
407     Map<String, List<Node>> actualNode = childNodesToNodeMap(orgNode);
408     assertStringField(childNodesToMap(actualNode.get(
409         Organization.Field.ADDRESS.toString()).get(0)), expected.getAddress()
410         .getFormatted(), Address.Field.FORMATTED);
411     assertStringField(actual, expected.getDescription(),
412         Organization.Field.DESCRIPTION);
413     // assertDateField(actual, expected.getEndDate(),
414     // Organization.Field.END_DATE);
415     assertStringField(actual, expected.getField(), Organization.Field.FIELD);
416     assertStringField(actual, expected.getName(), Organization.Field.NAME);
417     assertStringField(actual, expected.getSalary(), Organization.Field.SALARY);
418     // assertDateField(actual, expected.getStartDate(),
419     // Organization.Field.START_DATE);
420     assertStringField(actual, expected.getSubField(),
421         Organization.Field.SUB_FIELD);
422     assertStringField(actual, expected.getTitle(), Organization.Field.TITLE);
423     assertStringField(actual, expected.getWebpage(), Organization.Field.WEBPAGE);
424     assertStringField(actual, expected.getType(), Organization.Field.TYPE);
425   }
426 
427   private void assertBooleanField(Map<String, List<String>> result,
428       boolean expected, Object field) {
429     assertEquals(expected, Boolean.parseBoolean(result.get(field.toString())
430         .get(0)));
431   }
432 
433   private void assertFloatField(Map<String, List<String>> result,
434       Float expected, Object field) {
435     assertEquals(expected.floatValue(), Float.valueOf(result.get(
436         field.toString()).get(0)));
437   }
438 
439   private void assertStringField(Map<String, List<String>> result,
440       String expected, Object field) {
441     List<String> v = result.get(field.toString());
442     String t = null;
443     if ( v == null || v.size() == 0 ) {
444       if (expected == null ) {
445         return;
446       }
447       t = "";
448     } else {
449       t = v.get(0);
450     } 
451     assertEquals(expected, t);
452   }
453 
454   private void assertStringListField(Map<String, List<String>> result,
455       List<String> list, Person.Field field) {
456     assertEquals(list.size(), result.get(field.toString()).size());
457     for (int i = 0; i < list.size(); i++) {
458       assertEquals(list.get(i), result.get(field.toString()).get(i));
459     }
460   }
461 
462   private void assertEnumField(Map<String, List<Node>> result, Enum expected,
463       Person.Field field) {
464     Map<String, List<String>> actual = childNodesToMap(result.get(
465         field.toString()).get(0));
466     assertEquals(expected.getDisplayValue(), actual.get("displayValue").get(0));
467     assertEquals(expected.getValue().toString(), actual.get("value").get(0));
468   }
469 
470   private void assertListEnumField(Map<String, List<Node>> result,
471       List<? extends Enum<? extends Enum.EnumKey>> expected, Person.Field field) {
472     List<Node> actual = result.get(field.toString());
473     for (int i = 0; i < actual.size(); i++) {
474       Map<String, List<String>> nm = childNodesToMap(actual.get(i));
475       assertEquals(expected.get(i).getDisplayValue(), nm.get("displayValue")
476           .get(0));
477       assertEquals(expected.get(i).getValue().toString(), nm.get("value")
478           .get(0));
479     }
480   }
481 
482   /***
483    * Expected response for a list of people in json:
484    *
485    * { "totalResults" : 3,
486    *     "startIndex" : 0
487    *     "entry" : [ {<jane doe>}, // layed out like above
488    * {<george doe>}, {<maija m>}, ] }
489    *
490    * @throws Exception
491    *           if test encounters an error
492    */
493   @Test
494   public void testGetPeople() throws Exception {
495     Map<String, String> extraParams = Maps.newHashMap();
496     extraParams.put("sortBy", "name");
497     extraParams.put("sortOrder", null);
498     extraParams.put("filterBy", null);
499     extraParams.put("startIndex", null);
500     extraParams.put("count", "20");
501     extraParams.put("fields", null);
502 
503     // Currently, for Shindig @all == @friends
504     String resp = getResponse("/people/john.doe/@friends", "GET", extraParams,
505         "xml", "application/xml");
506     
507     XSDValidator.validate(resp, XMLSCHEMA, XSDRESOURCE,false);
508    
509     XPath xp = xpathFactory.newXPath();
510     NodeList resultNodeList = (NodeList) xp.evaluate("/response",
511         new InputSource(new StringReader(resp)), XPathConstants.NODESET);
512     assertEquals(1, resultNodeList.getLength());
513 
514     Map<String, List<String>> result = childNodesToMap(resultNodeList.item(0));
515     Map<String, List<Node>> resultNodes = childNodesToNodeMap(resultNodeList
516         .item(0));
517 
518     assertEquals("3", result.get("totalResults").get(0));
519     assertEquals("0", result.get("startIndex").get(0));
520 
521     // The users should be in alphabetical order
522     Map<String, List<Node>> entryOne = childNodesToNodeMap(resultNodes.get("entry").get(0));
523     
524     assertPerson(childNodesToNodeMap(entryOne.get("person").get(0)),
525         "george.doe", "George Doe");
526     
527     Map<String, List<Node>> entryTwo = childNodesToNodeMap(resultNodes.get("entry").get(1));
528     assertPerson(childNodesToNodeMap(entryTwo.get("person").get(0)),
529         "jane.doe", "Jane Doe");
530   }
531 
532   @Test
533   public void testGetPeoplePagination() throws Exception {
534     Map<String, String> extraParams = Maps.newHashMap();
535     extraParams.put("sortBy", "name");
536     extraParams.put("sortOrder", null);
537     extraParams.put("filterBy", null);
538     extraParams.put("startIndex", "0");
539     extraParams.put("count", "1");
540     extraParams.put("fields", null);
541 
542     String resp = getResponse("/people/john.doe/@friends", "GET", extraParams,
543         "xml", "application/xml");
544 
545     XSDValidator.validate(resp, XMLSCHEMA, XSDRESOURCE,false);
546 
547     XPath xp = xpathFactory.newXPath();
548     NodeList resultNodeList = (NodeList) xp.evaluate("/response",
549         new InputSource(new StringReader(resp)), XPathConstants.NODESET);
550     assertEquals(1, resultNodeList.getLength());
551 
552     Map<String, List<String>> result = childNodesToMap(resultNodeList.item(0));
553     Map<String, List<Node>> resultNodes = childNodesToNodeMap(resultNodeList
554         .item(0));
555 
556     assertEquals("3", result.get("totalResults").get(0));
557     assertEquals("0", result.get("startIndex").get(0));
558 
559     Map<String, List<Node>> entryOne = childNodesToNodeMap(resultNodes.get("entry").get(0));
560     
561     assertPerson(childNodesToNodeMap(entryOne.get("person").get(0)),
562         "george.doe", "George Doe");
563 
564     // Get the second page
565     extraParams.put("startIndex", "1");
566     resp = getResponse("/people/john.doe/@friends", "GET", extraParams, "xml",
567         "application/xml");
568     
569     XSDValidator.validate(resp, XMLSCHEMA, XSDRESOURCE,false);
570 
571     xp = xpathFactory.newXPath();
572     resultNodeList = (NodeList) xp.evaluate("/response", new InputSource(
573         new StringReader(resp)), XPathConstants.NODESET);
574     assertEquals(1, resultNodeList.getLength());
575 
576     result = childNodesToMap(resultNodeList.item(0));
577     resultNodes = childNodesToNodeMap(resultNodeList.item(0));
578 
579     assertEquals("3", result.get("totalResults").get(0));
580     assertEquals("1", result.get("startIndex").get(0));
581 
582     Map<String, List<Node>> entryTwo = childNodesToNodeMap(resultNodes.get("entry").get(0));
583     assertPerson(childNodesToNodeMap(entryTwo.get("person").get(0)),
584         "jane.doe", "Jane Doe");
585   }
586 
587   private void assertPerson(Map<String, List<Node>> person, String expectedId,
588       String expectedName) throws Exception {
589     assertEquals(expectedId, person.get("id").get(0).getTextContent());
590     assertEquals(expectedName, childNodesToMap(person.get("name").get(0)).get(
591         "unstructured").get(0));
592   }
593 
594   // TODO: Add tests for fields parameter
595   // TODO: Add tests for networkDistance
596 }