View Javadoc
1   /*
2    * Copyright (C) 2009 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 2.1 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.social.service.test;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.InputStreamReader;
23  import java.net.URI;
24  import java.util.Arrays;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.servlet.http.HttpServletRequest;
30  import javax.ws.rs.core.MultivaluedMap;
31  
32  import org.exoplatform.commons.utils.ListAccess;
33  import org.exoplatform.services.rest.ContainerResponseWriter;
34  import org.exoplatform.services.rest.impl.ContainerRequest;
35  import org.exoplatform.services.rest.impl.ContainerResponse;
36  import org.exoplatform.services.rest.impl.EnvironmentContext;
37  import org.exoplatform.services.rest.impl.InputHeadersMap;
38  import org.exoplatform.services.rest.impl.MultivaluedMapImpl;
39  import org.exoplatform.services.rest.tools.DummyContainerResponseWriter;
40  import org.exoplatform.social.common.RealtimeListAccess;
41  import org.exoplatform.social.core.activity.model.ActivityStream;
42  import org.exoplatform.social.core.activity.model.ExoSocialActivity;
43  import org.exoplatform.social.core.identity.model.Identity;
44  import org.exoplatform.social.core.identity.model.Profile;
45  import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
46  import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
47  import org.exoplatform.social.core.manager.ActivityManager;
48  import org.exoplatform.social.core.manager.IdentityManager;
49  import org.exoplatform.social.core.manager.RelationshipManager;
50  import org.exoplatform.social.core.profile.ProfileFilter;
51  import org.exoplatform.social.core.space.model.Space;
52  import org.exoplatform.social.core.space.spi.SpaceService;
53  import org.exoplatform.social.rest.entity.BaseEntity;
54  import org.exoplatform.social.rest.entity.DataEntity;
55  import org.exoplatform.social.service.rest.Util;
56  import org.exoplatform.social.service.rest.api.VersionResources;
57  import org.exoplatform.social.service.rest.api.models.ActivityRestListOut;
58  import org.exoplatform.social.service.rest.api.models.ActivityRestOut;
59  import org.exoplatform.social.service.rest.api.models.IdentityRestOut;
60  import org.exoplatform.ws.frameworks.json.impl.JsonDefaultHandler;
61  import org.exoplatform.ws.frameworks.json.impl.JsonException;
62  import org.exoplatform.ws.frameworks.json.impl.JsonGeneratorImpl;
63  import org.exoplatform.ws.frameworks.json.impl.JsonParserImpl;
64  import org.exoplatform.ws.frameworks.json.value.JsonValue;
65  
66  /**
67   * AbstractResourceTest.java <br>
68   * Provides <code>service</code> method to test rest service.
69   * @author <a href="http://hoatle.net">hoatle</a>
70   * @since Mar 3, 2010
71   */
72  public abstract class AbstractResourceTest extends AbstractServiceTest {
73  
74    public ContainerResponse getResponse(String method, String restPath, String input) throws Exception {
75      byte[] jsonData = input.getBytes("UTF-8");
76      MultivaluedMap<String, String> h = new MultivaluedMapImpl();
77      h.putSingle("content-type", "application/json");
78      h.putSingle("content-length", "" + jsonData.length);
79      
80      return service(method, restPath, "", h, jsonData);
81    }
82    
83    protected <T extends BaseEntity> T getBaseEntity(Object data, Class<T> clazz) throws Exception {
84      T entity = clazz.newInstance();
85      entity.setDataEntity((DataEntity) data);
86      return entity;
87    }
88  
89    protected String getURLResource(String resourceURL) {
90      return "/" + VersionResources.VERSION_ONE + "/social/" + resourceURL;
91    }
92  
93    /**
94     * gets response with provided writer
95     * @param method
96     * @param requestURI
97     * @param baseURI
98     * @param headers
99     * @param data
100    * @param writer
101    * @return
102    * @throws Exception
103    */
104   public ContainerResponse service(String method,
105                                    String requestURI,
106                                    String baseURI,
107                                    Map<String, List<String>> headers,
108                                    byte[] data,
109                                    String remoteUser,
110                                    ContainerResponseWriter writer) throws Exception {
111 
112     if (headers == null) {
113       headers = new MultivaluedMapImpl();
114     }
115 
116     ByteArrayInputStream in = null;
117     if (data != null) {
118       in = new ByteArrayInputStream(data);
119     }
120 
121     EnvironmentContext envctx = new EnvironmentContext();
122     HttpServletRequest httpRequest = new SocialMockHttpServletRequest("",
123                                                                       in,
124                                                                       in != null ? in.available() : 0,
125                                                                       method,
126                                                                       headers,
127                                                                       remoteUser);
128     envctx.put(HttpServletRequest.class, httpRequest);
129     EnvironmentContext.setCurrent(envctx);
130     ContainerRequest request = new ContainerRequest(method,
131                                                     new URI(requestURI),
132                                                     new URI(baseURI),
133                                                     in,
134                                                     new InputHeadersMap(headers));
135     ContainerResponse response = new ContainerResponse(writer);
136     requestHandler.handleRequest(request, response);
137     return response;
138   }
139 
140   /**
141    * gets response without provided writer
142    * @param method
143    * @param requestURI
144    * @param baseURI
145    * @param headers
146    * @param data
147    * @return
148    * @throws Exception
149    */
150   public ContainerResponse service(String method,
151                                    String requestURI,
152                                    String baseURI,
153                                    MultivaluedMap<String, String> headers,
154                                    byte[] data) throws Exception {
155     return service(method, requestURI, baseURI, headers, data, null, new DummyContainerResponseWriter());
156   }
157 
158   /**
159    * gets response without provided writer
160    * @param method
161    * @param requestURI
162    * @param baseURI
163    * @param headers
164    * @param data
165    * @return
166    * @throws Exception
167    */
168   public ContainerResponse service(String method,
169                                    String requestURI,
170                                    String baseURI,
171                                    MultivaluedMap<String, String> headers,
172                                    byte[] data,
173                                    String remoteUser) throws Exception {
174     return service(method, requestURI, baseURI, headers, data, remoteUser, new DummyContainerResponseWriter());
175   }
176 
177   /**
178    * gets response with provided writer
179    * @param method
180    * @param requestURI
181    * @param baseURI
182    * @param headers
183    * @param data
184    * @param writer
185    * @return
186    * @throws Exception
187    */
188   public ContainerResponse service(String method,
189                                    String requestURI,
190                                    String baseURI,
191                                    Map<String, List<String>> headers,
192                                    byte[] data,
193                                    ContainerResponseWriter writer) throws Exception {
194     return service(method, requestURI, baseURI, headers, data, null, writer);
195   }
196 
197   /**
198    * Asserts if the provided jsonString is equal to an entity object's string.
199    *
200    * @param jsonString the provided json string
201    * @param entity the provided entity object
202    */
203   public void assertJsonStringEqualsEntity(String jsonString, Object entity) throws JsonException {
204     JsonParserImpl jsonParser = new JsonParserImpl();
205     JsonDefaultHandler jsonDefaultHandler = new JsonDefaultHandler();
206     jsonParser.parse(new InputStreamReader(new ByteArrayInputStream(jsonString.getBytes())), jsonDefaultHandler);
207 
208     JsonValue firstJsonValue = jsonDefaultHandler.getJsonObject();
209     assertNotNull("firstJsonValue must not be null", firstJsonValue);
210 
211     JsonValue secondJsonValue = new JsonGeneratorImpl().createJsonObject(entity);
212     assertNotNull("secondJsonValue must not be null", secondJsonValue);
213 
214     assertEquals(firstJsonValue.toString(), secondJsonValue.toString());
215   }
216 
217   /**
218    * Asserts if the provided xmlString is equal to an entity object's string.
219    *
220    * @param xmlString the provided xml string
221    * @param entity the provided entity object
222    */
223   public void assertXmlStringEqualsEntity(String xmlString, Object entity) {
224     //TODO implement this
225   }
226 
227 
228   /**
229    * Tests: an anonymous user that accesses a resource requires authentication.
230    *
231    * @param method the http method string
232    * @param resourceUrl the resource url to access
233    * @param data the data if any
234    * @throws Exception
235    */
236   protected void testAccessResourceAsAnonymous(String method, String resourceUrl, MultivaluedMap<String,String> h, byte[] data) throws Exception {
237     testStatusCodeOfResource(null, method, resourceUrl, h, data, 401);
238 
239   }
240 
241 
242   /**
243    * Tests: an authenticated user that accesses a resource that is forbidden, has no permission.
244    *
245    * @param username the portal user name
246    * @param method the http method string
247    * @param resourceUrl the resource url to access
248    * @param data the data if any
249    * @throws Exception
250    */
251   protected void testAccessResourceWithoutPermission(String username, String method, String resourceUrl, byte[] data)
252                                                   throws Exception {
253     testStatusCodeOfResource(username, method, resourceUrl, null, data, 403);
254   }
255 
256 
257   /**
258    * Tests: an authenticated user that accesses a resource that is not found.
259    *
260    * @param username the portal user name
261    * @param method the http method string
262    * @param resourceUrl the resource url to access
263    * @param data the data if any
264    * @throws Exception
265    */
266   protected void testAccessNotFoundResourceWithAuthentication(String username, String method, String resourceUrl,
267                                                               byte[] data) throws Exception {
268     testStatusCodeOfResource(username, method, resourceUrl, null, data, 404);
269   }
270   
271   /**
272    * Tests if the return status code matches the response of the request with provided username, method, resourceUrl, headers, and data.
273    *
274    * @param username the portal user name if userName == null mean not authenticated.
275    * @param method the http method string
276    * @param resourceUrl the resource url to access
277    * @param h the header MultivalueMap
278    * @param data the data if any
279    * @param statusCode the expected status code of response
280    * @throws Exception
281    */
282   protected void testStatusCodeOfResource(String username, String method, String resourceUrl, 
283                                                               MultivaluedMap<String,String> h,
284                                                               byte[] data, int statusCode) throws Exception {
285     if(username != null){
286       startSessionAs(username);
287     } else {
288       endSession();
289     }
290     ContainerResponse containerResponse = service(method, resourceUrl, "", h, data);
291 
292     assertEquals("The response code of resource("+resourceUrl+") is not expected.)",statusCode, containerResponse.getStatus());
293   }
294   /**
295    * Comare ExoSocialActivity with entity HashMap
296    * @param activity
297    * @param entity
298    */
299   protected void compareActivity(ExoSocialActivity activity, HashMap<String, Object> entity){
300     assertNotNull("entity must not be null", entity);
301     
302     assertEquals("activity.getId() must equal:", activity.getId(), entity.get("id"));
303     
304     assertEquals("activity.getTitle() must equal: " + activity.getTitle() == null ? "" :activity.getTitle(),
305                   activity.getTitle() == null ? "" : activity.getTitle(),
306                   entity.get("title"));
307 
308     //TODO check this (Phuong)
309     /*
310     assertEquals("activity.getLikedByIdentities() size be equal:",
311                     activity.getLikeIdentityIds() == null ? 0 : activity.getLikeIdentityIds().length,
312                     ((ArrayList<HashMap<String, Object>>)entity.get("likedByIdentities")).size());
313     
314     String[] identityIds = activity.getLikeIdentityIds();
315     ArrayList<HashMap<String, Object>> likedIdentities = (ArrayList<HashMap<String, Object>>)entity.get("likedByIdentities");
316     if(identityIds != null){
317       for(int i = 0; i < identityIds.length; i++){
318         IdentityManager identityManager =  Util.getIdentityManager();
319         Identity likedIdentity = identityManager.getIdentity(identityIds[i],true);
320         compareIdentity(likedIdentity, likedIdentities.get(i));
321       }
322     }
323     */
324     
325     assertEquals("entity.getAppId() must equal: " + activity.getAppId() == null ? "" :activity.getAppId(),
326                   activity.getAppId() == null ? "" :activity.getAppId(), entity.get("appId"));
327     
328     assertEquals("activity.getType() must equal: " + activity.getType() == null ? "" : activity.getType(),
329                   activity.getType() == null ? "" : activity.getType(), entity.get("type"));
330     
331     assertEquals("entity.PostedTime() must equal: " + activity.getPostedTime() == null ? 0 : activity.getPostedTime(),
332                   activity.getPostedTime() == null ? 0 : activity.getPostedTime(),
333                   (Long) entity.get("postedTime"));
334     
335     assertTrue(((Long) entity.get("lastUpdated")).longValue() > 0);
336     
337     assertNotNull("entity.get(\"createdAt\"): ", entity.get("createdAt"));
338     
339     Float expectedPriority;
340     if(activity.getPriority() == null){
341       expectedPriority = new Float(0);
342     } else {
343       expectedPriority = activity.getPriority();
344     }
345     
346     assertEquals("activity.getPriority() must equal:",
347                   expectedPriority,
348                   entity.get("priority"));
349     assertEquals(activity.getTemplateParams() == null ? new HashMap() : activity.getTemplateParams(),
350                   entity.get("templateParams"));
351     assertEquals("activity.getTitleId() must return: " + activity.getTitleId() == null ? "" : activity.getTitleId(),
352                   activity.getTitleId() == null ? "" : activity.getTitleId() ,
353                   entity.get("titleId"));
354     Identity streamOwnerIdentity = Util.getOwnerIdentityIdFromActivity(activity);
355     assertEquals("activity.getIdentityId() must return: " + streamOwnerIdentity.getId() == null ? "" : streamOwnerIdentity.getId(),
356                   streamOwnerIdentity.getId() == null ? "" : streamOwnerIdentity.getId(),
357                   entity.get("identityId"));
358     
359     assertEquals("TotalNumberOfComments must be equal:",
360                   Util.getActivityManager().getCommentsWithListAccess(activity).getSize(),
361                   entity.get("totalNumberOfComments"));
362   }
363   /**
364    * Compares ActivityStream with entity HashMap
365    * @param activityStream
366    * @param entity
367    */
368   protected void compareActivityStream(ActivityStream activityStream, HashMap<String, Object> entity){
369     assertNotNull("entity must not be null", entity);
370     assertEquals("activityStream.getPrettyId() must equal: " + activityStream.getPrettyId() == null ? "" :activityStream.getPrettyId(),
371         activityStream.getPrettyId() == null ? "" : activityStream.getPrettyId(),
372         entity.get("prettyId"));
373     assertEquals("activityStream.getFaviconUrl() must equal: " + activityStream.getFaviconUrl() == null ? "" :activityStream.getPrettyId(),
374         activityStream.getFaviconUrl() == null ? "" : activityStream.getFaviconUrl(),
375         entity.get("faviconUrl"));
376     assertEquals("activityStream.getTitle() must equal: " + activityStream.getTitle() == null ? "" :activityStream.getTitle(),
377         activityStream.getTitle() == null ? "" : activityStream.getTitle(),
378         entity.get("title"));
379     assertEquals("activityStream.getPermaLink() must equal: " + activityStream.getPermaLink() == null ? "" : Util.getBaseUrl() + activityStream.getPermaLink(),
380         activityStream.getPermaLink() == null ? "" : Util.getBaseUrl() +  activityStream.getPermaLink(),
381         entity.get("permaLink"));
382   }
383   
384   /**
385    * Compares Identity with entity HashMap
386    * @param identity
387    * @param entity
388    */
389   protected void compareIdentity(Identity identity, HashMap<String, Object> entity){
390     assertNotNull("entity must not be null", entity);
391     assertEquals("identity.Id() must equal: " + identity.getId() == null ? "" :identity.getId(),
392         identity.getId() == null ? "" : identity.getId(),
393         entity.get("id"));
394     assertEquals("identity.getProviderId() must equal: " + identity.getProviderId() == null ? "" :identity.getProviderId(),
395         identity.getProviderId() == null ? "" : identity.getProviderId(),
396         entity.get("providerId"));
397     assertEquals("identity.getRemoteId() must equal: " + identity.getRemoteId() == null ? "" :identity.getRemoteId(),
398         identity.getRemoteId() == null ? "" : identity.getRemoteId(),
399         entity.get("remoteId"));
400     
401     HashMap<String, Object > profileEntity = (HashMap<String, Object>) entity.get("profile");
402     compareProfile(identity.getProfile(),profileEntity);
403   }
404   
405   /**
406    * Compares Profile with entity HashMap
407    * @param profile
408    * @param entity
409    */
410   protected void compareProfile(Profile profile, HashMap<String, Object> entity){
411     assertNotNull("entity must not be null", entity);
412     assertEquals("profile.getPrettyId() must equal: " + profile.getFullName() == null ? "" :profile.getFullName(),
413         profile.getFullName() == null ? "" : profile.getFullName(),
414         entity.get("fullName"));
415     assertTrue("profile.getAvatarUrl() must be start with \"http\" " + profile.getAvatarUrl() == null ? "" :profile.getAvatarUrl(),
416         ((String)entity.get("avatarUrl")).startsWith("http"));
417     //TODO: compare full default avatar URL/ absolute avatar URL
418   }
419   /**
420    * Compares ExoSocialActivity's comment with entity HashMap
421    * @param activity
422    * @param entity
423    */
424   protected void compareComment(ExoSocialActivity activity, HashMap<String, Object> entity){
425     assertNotNull("entity must not be null", entity);
426     assertEquals("activity.getId() must be equal:" + activity.getId() == null ? "" :activity.getId(),
427         activity.getId() == null ? "" :activity.getId(), entity.get("id"));
428     Identity posterIdentity = Util.getOwnerIdentityIdFromActivity(activity);
429     compareIdentity(posterIdentity, (HashMap<String, Object>) entity.get("posterIdentity"));
430     assertEquals("activity.getId() must be equal:" + activity.getTitle() == null ? "" :activity.getTitle(),
431         activity.getTitle() == null ? "" :activity.getTitle(), entity.get("text"));
432 
433     assertEquals("activity.getId() must be equal:" + activity.getPostedTime() == null ? 0 :activity.getPostedTime(),
434         activity.getPostedTime() == null ? 0 :activity.getPostedTime(), (Long) entity.get("postedTime"));
435   }
436 
437   /**
438    * Compares the list of activities.
439    *
440    * @param activityList the activity list
441    * @param responseEntity the response entity
442    */
443   protected void compareActivities(List<ExoSocialActivity> activityList, ActivityRestListOut responseEntity) {
444     List<ActivityRestOut> entityList = (List<ActivityRestOut>) responseEntity.
445                                                                get(ActivityRestListOut.Field.ACTIVITIES.toString());
446     assertEquals("entityList.size() must return: " + activityList.size(), activityList.size(), entityList.size());
447 
448     for (int i = 0; i < entityList.size(); i++) {
449       ExoSocialActivity activity = activityList.get(i);
450       ActivityRestOut entity = entityList.get(i);
451       compareActivity(activity, entity);
452     }
453 
454   }
455 
456   /**
457    * Compare number of comments.
458    *
459    * @param activityList
460    * @param responseEntity
461    * @param numberOfComments
462    */
463   protected void compareNumberOfComments(List<ExoSocialActivity> activityList, ActivityRestListOut responseEntity,
464                                          int numberOfComments) {
465     List<ActivityRestOut> entityList = (List<ActivityRestOut>) responseEntity.
466                                                                get(ActivityRestListOut.Field.ACTIVITIES.toString());
467     ActivityManager activityManager = (ActivityManager) getContainer().getComponentInstanceOfType(ActivityManager.class);
468     for (int i = 0; i < entityList.size(); i++) {
469       ExoSocialActivity activity = activityList.get(i);
470       int commentNumber = Math.min(numberOfComments, activityManager.getCommentsWithListAccess(activity).getSize());
471       ActivityRestOut entity = entityList.get(i);
472       assertEquals("entity.getComments().size() must return: " + commentNumber,
473               commentNumber,
474               entity.getComments().size()); 
475     }
476   }
477 
478 
479   /**
480    * Compare number of likes.
481    *
482    * @param activityList
483    * @param responseEntity
484    * @param numberOfLikes
485    */
486   protected void compareNumberOfLikes(List<ExoSocialActivity> activityList, ActivityRestListOut responseEntity,
487                                       int numberOfLikes) {
488     List<ActivityRestOut> entityList = (List<ActivityRestOut>) responseEntity.
489                                                                get(ActivityRestListOut.Field.ACTIVITIES.toString());
490     for (int i = 0; i < entityList.size(); i++) {
491       ExoSocialActivity activity = activityList.get(i);
492       int likeNumber = Math.min(numberOfLikes, activity.getLikeIdentityIds().length);
493       ActivityRestOut entity = entityList.get(i);
494       assertEquals("entity.getLikedByIdentities().size() must return: " + likeNumber,
495               likeNumber,
496               entity.getLikedByIdentities().size());
497       int activityLikedIdentityIdLength = activity.getLikeIdentityIds().length;
498       List<IdentityRestOut> likedByIdentities = entity.getLikedByIdentities();
499 
500       for (int j = 0; j < likedByIdentities.size(); j++) {
501         assertTrue("Likers must contain id " + likedByIdentities.get(j).getId(),
502                 Arrays.asList(activity.getLikeIdentityIds()).contains(likedByIdentities.get(j).getId()));
503       }
504 
505     }
506   }
507   
508   /**
509    * Compare number of likes.
510    *
511    * @param activity
512    * @param responseEntity
513    * @param numberOfLikes
514    */
515   protected void compareNumberOfLikes(ExoSocialActivity activity, ActivityRestOut responseEntity,
516                                       int numberOfLikes) {
517     int likeNumber = Math.min(numberOfLikes, activity.getLikeIdentityIds().length);
518     assertEquals("entity.getLikedByIdentities().size() must return: " + likeNumber,
519             likeNumber,
520             responseEntity.getLikedByIdentities().size());
521     int activityLikedIdentityIdLength = activity.getLikeIdentityIds().length;
522     List<IdentityRestOut> likedByIdentities = responseEntity.getLikedByIdentities();
523     for (int i = 0; i < likedByIdentities.size(); i++) {
524       assertEquals("likedByIdentities.get(i).getId() must return: " +
525                    activity.getLikeIdentityIds()[activityLikedIdentityIdLength - i - 1],
526                    activity.getLikeIdentityIds()[activityLikedIdentityIdLength - i - 1],
527                    likedByIdentities.get(i).getId());
528     }
529 
530   }
531 }