/* * Copyright (c) 2012 Socialize Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.socialize.test.integration.services.b; import android.app.Activity; import android.content.Context; import android.util.Log; import com.socialize.ConfigUtils; import com.socialize.ShareUtils; import com.socialize.Socialize; import com.socialize.UserUtils; import com.socialize.apache.http.entity.mime.HttpMultipartMode; import com.socialize.apache.http.entity.mime.MultipartEntity; import com.socialize.apache.http.entity.mime.content.ByteArrayBody; import com.socialize.apache.http.entity.mime.content.ContentBody; import com.socialize.api.SocializeSession; import com.socialize.api.action.share.SocialNetworkShareListener; import com.socialize.auth.AuthProviderResponse; import com.socialize.auth.AuthProviderType; import com.socialize.auth.UserProviderCredentials; import com.socialize.auth.twitter.TwitterAuthProvider; import com.socialize.auth.twitter.TwitterAuthProviderInfo; import com.socialize.config.SocializeConfig; import com.socialize.entity.Entity; import com.socialize.entity.ListResult; import com.socialize.entity.Share; import com.socialize.error.SocializeException; import com.socialize.ioc.SocializeIOC; import com.socialize.listener.AuthProviderListener; import com.socialize.listener.SocializeAuthListener; import com.socialize.listener.share.ShareListListener; import com.socialize.net.HttpRequestListener; import com.socialize.net.HttpRequestProvider; import com.socialize.networks.PostData; import com.socialize.networks.SocialNetwork; import com.socialize.networks.SocialNetworkListener; import com.socialize.networks.SocialNetworkPostListener; import com.socialize.networks.twitter.*; import com.socialize.test.SocializeActivityTest; import com.socialize.test.util.TestUtils; import com.socialize.util.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.ProtocolVersion; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicStatusLine; import org.json.JSONObject; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * @author Jason Polites * */ public class TwitterUtilsTest extends SocializeActivityTest { public void test_link () throws Throwable { final CountDownLatch latch = new CountDownLatch(1); final Activity context = TestUtils.getActivity(this); // Stub in the TwitterAuthProvider TwitterAuthProvider mockTwitterAuthProvider = new TwitterAuthProvider() { @Override public void authenticate(Context context, TwitterAuthProviderInfo info, AuthProviderListener listener) { addResult(0, info); latch.countDown(); } }; SocializeIOC.registerStub("twitterProvider", mockTwitterAuthProvider); // Set a mock key/secret TwitterUtils.setCredentials(TestUtils.getActivity(this), "foo", "bar"); // Ensure we don't have a session TwitterUtils.unlink(TestUtils.getActivity(this)); // Validate assertFalse(TwitterUtils.isLinked(getContext())); // Now Link TwitterUtils.link(context, null); latch.await(10, TimeUnit.SECONDS); TwitterAuthProviderInfo data = getResult(0); assertNotNull(data); assertEquals(AuthProviderType.TWITTER, data.getType()); assertEquals("foo", data.getConsumerKey()); assertEquals("bar", data.getConsumerSecret()); SocializeIOC.unregisterStub("twitterProvider"); } public void test_link_with_token () throws Exception { final CountDownLatch latch = new CountDownLatch(1); final Activity context = TestUtils.getActivity(this); // Stub in the TwitterAuthProvider to ensure we DON'T auth with TW TwitterAuthProvider mockTwitterAuthProvider = new TwitterAuthProvider() { @Override public void authenticate(Context context, TwitterAuthProviderInfo info, AuthProviderListener listener) { addResult(1, "fail"); } }; SocializeIOC.registerStub("twitterProvider", mockTwitterAuthProvider); final String token = TestUtils.getDummyTwitterToken(context); final String secret = TestUtils.getDummyTwitterSecret(context); assertNotNull(token); assertNotNull(secret); assertFalse(StringUtils.isEmpty(token)); assertFalse(StringUtils.isEmpty(secret)); TwitterUtils.link(context, token, secret, new SocializeAuthListener() { @Override public void onError(SocializeException error) { Log.e("Socialize", error.getMessage(), error); addResult(1, "fail"); latch.countDown(); } @Override public void onCancel() { addResult(1, "fail"); latch.countDown(); } @Override public void onAuthSuccess(SocializeSession session) { addResult(0, session); latch.countDown(); } @Override public void onAuthFail(SocializeException error) { Log.e("Socialize", error.getMessage(), error); addResult(1, "fail"); } }); latch.await(10, TimeUnit.SECONDS); SocializeSession session = getResult(0); String fail = getResult(1); assertNull(fail); assertNotNull(session); UserProviderCredentials userProviderCredentials = session.getUserProviderCredentials(AuthProviderType.TWITTER); assertNotNull(userProviderCredentials); assertEquals(token, userProviderCredentials.getAccessToken()); assertEquals(secret, userProviderCredentials.getTokenSecret()); assertTrue(TwitterUtils.isLinked(context)); assertEquals(token, TwitterUtils.getAccessToken(context)); assertEquals(secret, TwitterUtils.getTokenSecret(context)); SocializeIOC.unregisterStub("twitterProvider"); } public void test_isAvailable() { ConfigUtils.getConfig(getContext()).setTwitterKeySecret("foo", "bar"); assertTrue(TwitterUtils.isAvailable(getContext())); ConfigUtils.getConfig(getContext()).setTwitterKeySecret(null, null); assertFalse(TwitterUtils.isAvailable(getContext())); } public void test_setCredentials() { String consumerKey = "foo"; String consumerSecret = "bar"; TwitterUtils.setCredentials(getContext(), consumerKey, consumerSecret); assertEquals(consumerKey, ConfigUtils.getConfig(getContext()).getProperty(SocializeConfig.TWITTER_CONSUMER_KEY)); assertEquals(consumerSecret, ConfigUtils.getConfig(getContext()).getProperty(SocializeConfig.TWITTER_CONSUMER_SECRET)); } public void test_post_authed() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final String token = TestUtils.getDummyTwitterToken(getContext()); final String secret = TestUtils.getDummyTwitterSecret(getContext()); // Stub in the TwitterAuthProvider TwitterAuthProvider mockTwitterAuthProvider = new TwitterAuthProvider() { @Override public void authenticate(Context context, TwitterAuthProviderInfo info, AuthProviderListener listener) { AuthProviderResponse response = new AuthProviderResponse(); response.setToken(token); response.setSecret(secret); listener.onAuthSuccess(response); } }; SocializeIOC.registerStub("twitterProvider", mockTwitterAuthProvider); TwitterUtils.link(getContext(), new SocializeAuthListener() { @Override public void onError(SocializeException error) { error.printStackTrace(); addResult(0, "fail"); } @Override public void onCancel() { addResult(0, "fail"); } @Override public void onAuthSuccess(SocializeSession session) { latch.countDown(); } @Override public void onAuthFail(SocializeException error) { error.printStackTrace(); latch.countDown(); } }); assertTrue(latch.await(10, TimeUnit.SECONDS)); assertNull(getResult(0)); do_test_post(); } public void test_post_not_authed() throws Exception { Socialize.getSocialize().clearSessionCache(getContext()); do_test_post(); } public void testTweetPhoto() { final CustomMultipartEntity entity = new CustomMultipartEntity(); TwitterUtilsImpl utils = new TwitterUtilsImpl() { @Override protected void post(Activity context, String resource, HttpEntity entity, SocialNetworkPostListener listener) { addResult(0, resource); addResult(1, entity); addResult(2, listener); } @Override protected MultipartEntity newMultipartEntity(HttpMultipartMode mode) { return entity; } }; PhotoTweet tweet = new PhotoTweet(); tweet.setImageData(new byte[] {1,2,3}); tweet.setText("foobar"); SocialNetworkPostListener listener = new SocialNetworkPostListener() { @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) {} @Override public void onCancel() {} @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {} }; SocializeConfig config = new SocializeConfig(); config.setProperty("twitter.upload.endpoint", "foobar/"); utils.setConfig(config); utils.tweetPhoto(TestUtils.getActivity(this), tweet, listener); String resource = getResult(0); HttpEntity entityAfter = getResult(1); SocialNetworkPostListener listenerAfter = getResult(2); assertNotNull(resource); assertNotNull(entityAfter); assertNotNull(listenerAfter); assertSame(listener, listenerAfter); assertSame(entity, entityAfter); assertEquals("foobar/statuses/update_with_media.json", resource); assertTrue(entityAfter instanceof CustomMultipartEntity); CustomMultipartEntity ce = (CustomMultipartEntity) entityAfter; Map<String, ContentBody> parts = ce.parts; assertNotNull(parts); ContentBody mediaBody = parts.get("media"); ContentBody statusBody = parts.get("status"); ContentBody possibly_sensitiveBody = parts.get("possibly_sensitive"); assertNotNull(mediaBody); assertNotNull(statusBody); assertNotNull(possibly_sensitiveBody); assertTrue(mediaBody instanceof ByteArrayBody); } public void testTweetPhotoFlowAuthed() { TwitterUtilsImpl proxy = new TwitterUtilsImpl() { @Override public boolean isLinked(Context context) { return true; } @Override public void tweetPhoto(Activity context, PhotoTweet tweet, SocialNetworkPostListener listener) { addResult(0, "tweetPhoto"); } }; TwitterAccess.setTwitterUtilsProxy(proxy); PhotoTweet tweet = new PhotoTweet(); tweet.setImageData(new byte[] {1,2,3}); tweet.setText("foobar"); TwitterUtils.tweetPhoto(TestUtils.getActivity(this), tweet, null); String tweetPhoto = getResult(0); assertNotNull(tweetPhoto); assertEquals("tweetPhoto", tweetPhoto); } enum LISTENER_ACTION {AUTH_SUCCESS, ERROR, CANCEL}; public void testTweetPhotoFlowNotAuthed() { doTestTweetPhotoFlowNotAuthed(LISTENER_ACTION.AUTH_SUCCESS); TestUtils.clear(); doTestTweetPhotoFlowNotAuthed(LISTENER_ACTION.ERROR); TestUtils.clear(); doTestTweetPhotoFlowNotAuthed(LISTENER_ACTION.CANCEL); } protected void doTestTweetPhotoFlowNotAuthed(final LISTENER_ACTION action) { TwitterUtilsImpl proxy = new TwitterUtilsImpl() { @Override public boolean isLinked(Context context) { return false; } @Override public void tweetPhoto(Activity context, PhotoTweet tweet, SocialNetworkPostListener listener) { addResult(0, "tweetPhoto"); } @Override public void link(Activity context, SocializeAuthListener listener) { switch (action) { case AUTH_SUCCESS: listener.onAuthSuccess(null); break; case CANCEL: listener.onCancel(); break; case ERROR: listener.onError(null); break; } } }; TwitterAccess.setTwitterUtilsProxy(proxy); PhotoTweet tweet = new PhotoTweet(); tweet.setImageData(new byte[] {1,2,3}); tweet.setText("foobar"); TwitterUtils.tweetPhoto(TestUtils.getActivity(this), tweet, new SocialNetworkPostListener() { @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) { addResult(1, "onNetworkError"); } @Override public void onCancel() { addResult(2, "onCancel"); } @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {} }); String tweetPhoto = getResult(0); String onNetworkError = getResult(1); String onCancel = getResult(2); switch (action) { case AUTH_SUCCESS: assertNull(onNetworkError); assertNull(onCancel); assertNotNull(tweetPhoto); assertEquals("tweetPhoto", tweetPhoto); break; case CANCEL: assertNull(onNetworkError); assertNull(tweetPhoto); assertNotNull(onCancel); assertEquals("onCancel", onCancel); break; case ERROR: assertNull(tweetPhoto); assertNull(onCancel); assertNotNull(onNetworkError); assertEquals("onNetworkError", onNetworkError); break; } } public void testTweetFlowNotAuthed() { doTestTweetFlowNotAuthed(LISTENER_ACTION.AUTH_SUCCESS); TestUtils.clear(); doTestTweetFlowNotAuthed(LISTENER_ACTION.ERROR); TestUtils.clear(); doTestTweetFlowNotAuthed(LISTENER_ACTION.CANCEL); } protected void doTestTweetFlowNotAuthed(final LISTENER_ACTION action) { TwitterUtilsImpl proxy = new TwitterUtilsImpl() { @Override public boolean isLinked(Context context) { return false; } @Override public void post(Activity context, String resource, Map<String, Object> postData, SocialNetworkPostListener listener) { addResult(0, "tweeted"); } @Override public void link(Activity context, SocializeAuthListener listener) { switch (action) { case AUTH_SUCCESS: listener.onAuthSuccess(null); break; case CANCEL: listener.onCancel(); break; case ERROR: listener.onError(null); break; } } }; TwitterAccess.setTwitterUtilsProxy(proxy); Tweet tweet = new Tweet(); tweet.setText("foobar"); TwitterUtils.tweet(TestUtils.getActivity(this), tweet, new SocialNetworkListener() { @Override public boolean onBeforePost(Activity parent, SocialNetwork socialNetwork, PostData postData) { addResult(1, "onBeforePost"); return false; } @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) { addResult(2, "onNetworkError"); } @Override public void onCancel() { addResult(3, "onCancel"); } @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {} }); String tweeted = getResult(0); String onBeforePost = getResult(1); String onNetworkError = getResult(2); String onCancel = getResult(3); switch (action) { case AUTH_SUCCESS: assertNull(onNetworkError); assertNull(onCancel); assertNotNull(onBeforePost); assertNotNull(tweeted); assertEquals("tweeted", tweeted); break; case CANCEL: assertNull(onNetworkError); assertNull(tweeted); assertNull(onBeforePost); assertNotNull(onCancel); assertEquals("onCancel", onCancel); break; case ERROR: assertNull(tweeted); assertNull(onCancel); assertNull(onBeforePost); assertNotNull(onNetworkError); assertEquals("onNetworkError", onNetworkError); break; } } public void testPostFlowNotAuthed() { doTestPostFlowNotAuthed(LISTENER_ACTION.AUTH_SUCCESS); TestUtils.clear(); doTestPostFlowNotAuthed(LISTENER_ACTION.ERROR); TestUtils.clear(); doTestPostFlowNotAuthed(LISTENER_ACTION.CANCEL); } public void testTweetUsesCustomPath() { final String path = "foobar_path"; TwitterUtilsImpl twitterUtils = new TwitterUtilsImpl() { @Override protected void post(final Activity context, String resource, HttpEntity entity, final SocialNetworkPostListener listener) { addResult(0, resource); } }; SocialNetworkListener listener = new SocialNetworkListener() { @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) {} @Override public void onCancel() {} @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {} @Override public boolean onBeforePost(Activity parent, SocialNetwork socialNetwork, PostData postData) { postData.setPath(path); return false; } }; Tweet tweet = new Tweet(); tweet.setShareLocation(false); tweet.setText("foobar"); SocializeConfig mockConfig = new SocializeConfig(); mockConfig.setProperty("twitter.api.endpoint", "mock"); twitterUtils.setConfig(mockConfig); twitterUtils.tweet(TestUtils.getActivity(this), tweet, listener); String result = getResult(0); assertEquals("mock"+path, result); } protected void doTestPostFlowNotAuthed(final LISTENER_ACTION action) { TwitterUtilsImpl proxy = new TwitterUtilsImpl() { @Override public boolean isLinked(Context context) { return false; } @Override public void post(Activity context, String resource, Map<String, Object> postData, SocialNetworkPostListener listener) { addResult(0, resource); } @Override public void link(Activity context, SocializeAuthListener listener) { switch (action) { case AUTH_SUCCESS: listener.onAuthSuccess(null); break; case CANCEL: listener.onCancel(); break; case ERROR: listener.onError(null); break; } } }; TwitterAccess.setTwitterUtilsProxy(proxy); String resource = "foobar"; Map<String, Object> postData = new HashMap<String, Object>(); TwitterUtils.post(TestUtils.getActivity(this), resource, postData, new SocialNetworkPostListener() { @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) { addResult(2, "onNetworkError"); } @Override public void onCancel() { addResult(3, "onCancel"); } @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {} }); String post = getResult(0); String onNetworkError = getResult(2); String onCancel = getResult(3); switch (action) { case AUTH_SUCCESS: assertNull(onNetworkError); assertNull(onCancel); assertNotNull(post); assertEquals(resource, post); break; case CANCEL: assertNull(onNetworkError); assertNull(post); assertNotNull(onCancel); assertEquals("onCancel", onCancel); break; case ERROR: assertNull(post); assertNull(onCancel); assertNotNull(onNetworkError); assertEquals("onNetworkError", onNetworkError); break; } } protected void do_test_post() throws Exception { String entityKeyRandom = "foobar" + Math.random(); Entity entity = Entity.newInstance(entityKeyRandom, "foobar"); final CountDownLatch latch = new CountDownLatch(1); final String token = TestUtils.getDummyTwitterToken(getContext()); final String secret = TestUtils.getDummyTwitterSecret(getContext()); // Stub in the TwitterAuthProvider TwitterAuthProvider mockTwitterAuthProvider = new TwitterAuthProvider() { @Override public void authenticate(Context context, TwitterAuthProviderInfo info, AuthProviderListener listener) { AuthProviderResponse response = new AuthProviderResponse(); response.setToken(token); response.setSecret(secret); listener.onAuthSuccess(response); } }; final HttpResponse mockResponse = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("https", 1, 0), 200, "")); final String responseData = "{foo:bar}"; // Stub in the http provider factory for the tweet HttpRequestProvider mockProvider = new HttpRequestProvider() { @Override public void post(HttpPost request, HttpRequestListener listener) { listener.onSuccess(mockResponse, responseData); } @Override public void get(HttpGet request, HttpRequestListener listener) { listener.onSuccess(mockResponse, responseData); } }; SocializeIOC.registerStub("twitterProvider", mockTwitterAuthProvider); SocializeIOC.registerStub("httpRequestProvider", mockProvider); TwitterUtils.tweetEntity(TestUtils.getActivity(this), entity, "AndroidSDK Test", new SocialNetworkShareListener() { @Override public void onNetworkError(Activity context, SocialNetwork network, Exception error) { error.printStackTrace(); latch.countDown(); } @Override public boolean onBeforePost(Activity parent, SocialNetwork socialNetwork, PostData postData) { addResult(3, "onBeforePost"); return false; } @Override public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject response) { addResult(1, "onAfterPost"); latch.countDown(); } @Override public void onCancel() {} }); assertTrue(latch.await(20, TimeUnit.SECONDS)); final CountDownLatch latch2 = new CountDownLatch(1); // Make sure we have a share object ShareUtils.getSharesByUser(getContext(), UserUtils.getCurrentUser(getContext()), 0, 100, new ShareListListener() { @Override public void onList(ListResult<Share> entities) { addResult(2, entities); latch2.countDown(); } @Override public void onError(SocializeException error) { error.printStackTrace(); latch2.countDown(); } }); assertTrue(latch2.await(20, TimeUnit.SECONDS)); SocializeIOC.unregisterStub("twitterProvider"); String onAfterPost = getResult(1); ListResult<Share> shares = getResult(2); String onBeforePost = getResult(3); assertNotNull(onAfterPost); assertNotNull(shares); assertNotNull(onBeforePost); // Find the share assertTrue(shares.size() > 0); List<Share> items = shares.getItems(); Share match = null; for (Share share : items) { if(share.getEntity().getKey().equals(entityKeyRandom)) { match = share; break; } } assertNotNull(match); } class CustomMultipartEntity extends MultipartEntity { Map<String, ContentBody> parts = new HashMap<String, ContentBody>(); @Override public void addPart(String name, ContentBody contentBody) { parts.put(name, contentBody); super.addPart(name, contentBody); } } }