/*
* 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);
}
}
}