package com.zulip.android.test; import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.test.ActivityUnitTestCase; import com.j256.ormlite.dao.RuntimeExceptionDao; import com.j256.ormlite.misc.TransactionManager; import com.zulip.android.ZulipApp; import com.zulip.android.activities.MessageListFragment; import com.zulip.android.activities.ZulipActivity; import com.zulip.android.models.Message; import com.zulip.android.models.MessageRange; import com.zulip.android.models.MessageType; import com.zulip.android.models.Person; import com.zulip.android.test.mutated.FakeAsyncGetOldMessages; import com.zulip.android.util.MessageListener.LoadPosition; import org.json.JSONException; import org.json.JSONObject; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; public class UnsortedTests extends ActivityUnitTestCase<ZulipActivity> { private static final String TESTUSER_EXAMPLE_COM = "testuser@example.com"; private ZulipApp app; private RuntimeExceptionDao<Message, Object> messageDao; public UnsortedTests() { super(ZulipActivity.class); } protected void setUp() throws Exception { super.setUp(); app = new ZulipApp(); } public void testMessageCreation() throws JSONException { prepTests(); JSONObject jsonObject; jsonObject = new JSONObject( "{\"recipient_id\": 314, \"sender_email\": \"lfaraone@zulip.com\", \"timestamp\": 1379966441, \"display_recipient\": \"test\", \"sender_id\": 15, \"sender_full_name\": \"Luke Faraone\", \"sender_domain\": \"zulip.com\", \"content\": \"Hello!\", \"gravatar_hash\": \"9cd8e1981dc89f3221c5077dd8a22515\", \"avatar_url\": \"https://secure.gravatar.com/avatar/9cd8e1981dc89f3221c5077dd8a22515?d=identicon\", \"client\": \"website\", \"content_type\": \"text/x-markdown\", \"subject_links\": [], \"sender_short_name\": \"lfaraone\", \"type\": \"stream\", \"id\": 10594623, \"subject\": \"toast\"}"); Message msg = new Message((ZulipApp) getActivity().getApplication(), jsonObject); assertEquals(msg.getID(), 10594623); assertEquals(msg.getSender(), new Person("Luke Faraone", "lfaraone@zulip.com")); } private void checkRanges(String rangestr) throws SQLException { List<MessageRange> ranges = app.getDao(MessageRange.class) .queryBuilder().orderBy("low", true).query(); String s = ""; for (MessageRange rng : ranges) { s += "(" + rng.low + "," + rng.high + ")"; } assertEquals(rangestr, s); } public void testMessageRange() throws SQLException { prepTests(); MessageRange.markRange(app, 100, 200); checkRanges("(100,200)"); MessageRange.markRange(app, 50, 60); checkRanges("(50,60)(100,200)"); MessageRange.markRange(app, 58, 70); checkRanges("(50,70)(100,200)"); MessageRange.markRange(app, 70, 100); checkRanges("(50,200)"); MessageRange.markRange(app, 40, 49); checkRanges("(40,200)"); MessageRange.markRange(app, 201, 210); checkRanges("(40,210)"); } public void testUpdateMessageRange() throws SQLException { prepTests(); app.setMaxMessageId(1000); MessageRange.updateNewMessagesRange(app, 1010); checkRanges("(1000,1010)"); MessageRange.updateNewMessagesRange(app, 1020); checkRanges("(1000,1020)"); // Then, after we skip some messages... app.setMaxMessageId(2000); MessageRange.updateNewMessagesRange(app, 2010); checkRanges("(1000,1020)(2000,2010)"); } public void testMessageTrim() throws SQLException { prepTests(); TransactionManager.callInTransaction(app.getDatabaseHelper() .getConnectionSource(), new Callable<Void>() { public Void call() throws Exception { for (int i = 1; i <= 300; i++) { sampleMessage(app, i); } for (int i = 501; i <= 800; i++) { sampleMessage(app, i); } app.getDao(MessageRange.class).create(new MessageRange(1, 300)); app.getDao(MessageRange.class).create( new MessageRange(501, 800)); return null; } }); RuntimeExceptionDao<MessageRange, Integer> messageRangeDao = app .getDao(MessageRange.class); assertEquals(600, messageDao.countOf()); Message.trim(100, app); this.messageDao.queryForAll(); assertEquals(100, messageDao.countOf()); assertEquals(1, messageRangeDao.countOf()); MessageRange r = messageRangeDao.queryBuilder().queryForFirst(); // We have messages 701 through 800, which is 100 messages. assertEquals(800, r.high); assertEquals(800 - 99, r.low); } public void testAGOMFetch() throws SQLException, InterruptedException, ExecutionException { prepTests(); MessageListFragment fragment = MessageListFragment.newInstance(null); fragment.app = app; FakeAsyncGetOldMessages request = new FakeAsyncGetOldMessages(fragment); request.setShouldFmSucceed(true); request.appendTheseMessages = new ArrayList<Message>(); Message m1 = sampleMessage(app, 40); Message m2 = sampleMessage(app, 45); Message m3 = sampleMessage(app, 60); request.appendTheseMessages.add(m1); request.appendTheseMessages.add(m2); request.appendTheseMessages.add(m3); request.execute(50, LoadPosition.INITIAL, 10, 10, null); request.get(); // Should result in a MR of 40, 60 MessageRange mr = app.getDao(MessageRange.class).queryForAll().get(0); assertEquals(40, mr.low); assertEquals(60, mr.high); // Now fetching inside that range should be safe. request = new FakeAsyncGetOldMessages(fragment); request.execute(45, LoadPosition.INITIAL, 1, 0, null); request.get(); assertFalse(request.isFmCalled()); assertEquals(2, request.receivedMessages.size()); // Now let's test coalescing... // The fetch won't be in cache here, but one message will already be // retrieved. request = new FakeAsyncGetOldMessages(fragment); request.setShouldFmSucceed(true); request.appendTheseMessages = new ArrayList<Message>(); Message m0 = sampleMessage(app, 35); request.appendTheseMessages.add(m0); request.appendTheseMessages.add(m1); request.execute(36, LoadPosition.INITIAL, 1, 1, null); request.get(); assertEquals(2, request.receivedMessages.size()); List<MessageRange> mrs = app.getDao(MessageRange.class).queryForAll(); assertEquals(1, mrs.size()); assertEquals(35, mrs.get(0).low); assertEquals(60, mrs.get(0).high); // And test partial hits for good measure! request = new FakeAsyncGetOldMessages(fragment); request.setShouldFmSucceed(true); request.execute(36, LoadPosition.INITIAL, 2, 0, null); request.get(); // 35 should be in cache assertEquals(1, request.receivedMessages.size()); assertEquals(false, request.isFmCalled()); // Recursing in one direction assertEquals(1, request.recurseRequestsReceived.size()); request = request.recurseRequestsReceived.get(0); request.setShouldFmSucceed(true); assertEquals(1, request.getFmNumBefore()); request.appendTheseMessages = new ArrayList<Message>(); Message mn1 = sampleMessage(app, 33); request.appendTheseMessages.add(mn1); request.executeBasedOnPresetValues(); request.get(); assertEquals(true, request.isFmCalled()); assertEquals(1, request.receivedMessages.size()); mrs = app.getDao(MessageRange.class).queryForAll(); assertEquals(1, mrs.size()); assertEquals(33, mrs.get(0).low); } private Message sampleMessage(ZulipApp app, int id) throws SQLException { Message rtr = new Message(app); rtr.setSender(Person.getOrUpdate(app, "Test User", TESTUSER_EXAMPLE_COM, "", 0)); rtr.setContent("Test message"); rtr.setType(MessageType.PRIVATE_MESSAGE); rtr.setRecipient(new String[]{TESTUSER_EXAMPLE_COM}); rtr.setID(id); messageDao.create(rtr); return rtr; } /** * Run this before each test to set up the activity. */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void prepTests() { setApplication(app); this.startActivity(new Intent(getInstrumentation().getTargetContext(), ZulipActivity.class), null, null); this.getInstrumentation().waitForIdleSync(); app.setContext(getInstrumentation().getTargetContext()); // Need to setEmail twice to reinitialise the database after destroying // it. app.setEmail(TESTUSER_EXAMPLE_COM); app.deleteDatabase(app.getDatabaseHelper().getDatabaseName()); app.setEmail(TESTUSER_EXAMPLE_COM); messageDao = app.getDao(Message.class); } protected void tearDown() throws Exception { super.tearDown(); } }