/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.slick.msghistory; import java.util.*; import junit.framework.*; import net.java.sip.communicator.impl.protocol.mock.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.history.*; import net.java.sip.communicator.service.msghistory.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; import org.osgi.framework.*; import com.google.common.xml.*; /** * Tests message history. * First installs the MoxkProtocolProvider to be able to send some messages * The message history service stores them * and then tests the verious find methods - does they find the messsages we have * already sent * * @author Damian Minkov */ public class TestMsgHistoryService extends TestCase { private static final Logger logger = Logger.getLogger(TestMsgHistoryService.class); static final String TEST_CONTACT_NAME_1 = "Mincho_Penchev_the_fisrt"; static final String TEST_CONTACT_NAME_2 = "Mincho_Penchev_the_second"; static final String TEST_ROOM_NAME = "test_room"; /** * The provider that we use to make a dummy server-stored contactlist * used for testing. The mockProvider is instantiated and registered * by the metacontactlist slick activator. */ public static MockProvider mockProvider = null; /** * The persistent presence operation set of the default mock provider. */ public static MockPersistentPresenceOperationSet mockPresOpSet = null; public static MockBasicInstantMessaging mockBImOpSet = null; public static MockMultiUserChat mockMultiChat = null; private static ServiceReference msgHistoryServiceRef = null; public static MessageHistoryService msgHistoryService = null; public static HistoryService historyService = null; private static MockContact testContact = null; private static ServiceReference metaCLref = null; private static MetaContactListService metaClService = null; private static MetaContact testMetaContact = null; /** * A reference to the registration of the first mock provider. */ public static ServiceRegistration mockPrServiceRegistration = null; private static Message[] messagesToSend = null; private static Date controlDate1 = null; private static Date controlDate2 = null; private static Object lock = new Object(); public TestMsgHistoryService(String name) { super(name); } public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest( new TestMsgHistoryService("readRecords")); suite.addTest( new TestMsgHistoryService("specialChars")); suite.addTest( new TestMsgHistoryService("insertRecords")); return suite; } @Override protected void setUp() throws Exception { setupContact(); msgHistoryService.eraseLocallyStoredHistory(); historyService.purgeLocallyCachedHistories(); writeRecords(); } @Override protected void tearDown() throws Exception { metaClService.purgeLocallyStoredContactListCopy(); } public void setupContact() { // changes the history service target derictory System.setProperty("HistoryServiceDirectory", "test-msghistory"); mockProvider = new MockProvider("MessageHistoryMockUser"); //store thre presence op set of the new provider into the fixture Map<String, OperationSet> supportedOperationSets = mockProvider.getSupportedOperationSets(); //get the operation set presence here. mockPresOpSet = (MockPersistentPresenceOperationSet) supportedOperationSets.get( OperationSetPersistentPresence.class.getName()); mockBImOpSet = (MockBasicInstantMessaging) supportedOperationSets.get( OperationSetBasicInstantMessaging.class.getName()); mockMultiChat = (MockMultiUserChat) supportedOperationSets.get( OperationSetMultiUserChat.class.getName()); msgHistoryServiceRef = MsgHistoryServiceLick.bc. getServiceReference(MessageHistoryService.class.getName()); msgHistoryService = (MessageHistoryService)MsgHistoryServiceLick.bc. getService(msgHistoryServiceRef); ServiceReference historyServiceRef = MsgHistoryServiceLick.bc. getServiceReference(HistoryService.class.getName()); historyService = (HistoryService)MsgHistoryServiceLick.bc. getService(historyServiceRef); // fill in a contact to comunicate with MockContactGroup root = (MockContactGroup)mockPresOpSet.getServerStoredContactListRoot(); testContact = new MockContact(TEST_CONTACT_NAME_1, mockProvider); root.addContact(testContact); metaCLref = MsgHistoryServiceLick.bc.getServiceReference( MetaContactListService.class.getName()); metaClService = (MetaContactListService)MsgHistoryServiceLick.bc.getService(metaCLref); System.setProperty(MetaContactListService.PROVIDER_MASK_PROPERTY, "1"); Hashtable<String, String> mockProvProperties = new Hashtable<String, String>(); mockProvProperties.put(ProtocolProviderFactory.PROTOCOL , mockProvider.getProtocolName()); mockProvProperties.put(MetaContactListService.PROVIDER_MASK_PROPERTY, "1"); mockPrServiceRegistration = MsgHistoryServiceLick.bc.registerService( ProtocolProviderService.class.getName(), mockProvider, mockProvProperties); logger.debug("Registered a mock protocol provider! "); testMetaContact = metaClService.getRoot(). getMetaContact(mockProvider, TEST_CONTACT_NAME_1); // add one more contact as specific problems may happen only when // more than one contact is in the metacontact metaClService.addNewContactToMetaContact( mockProvider, testMetaContact, TEST_CONTACT_NAME_2); messagesToSend = new Message[] { mockBImOpSet.createMessage("test message word1-" + Math.random()), mockBImOpSet.createMessage("test message word2" + Math.random()), mockBImOpSet.createMessage("test message word3" + Math.random()), mockBImOpSet.createMessage("test message word4" + Math.random()), mockBImOpSet.createMessage("test message word5" + Math.random()), mockBImOpSet.createMessage("Hello \u0002World\u0002!"), mockBImOpSet.createMessage("less than < this, greater than > and an ampersand &") }; } /** * First send the messages */ public void writeRecords() { logger.info("write records "); assertNotNull("No metacontact", testMetaContact); // First deliver message, so they are stored by the message history service mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_1, messagesToSend[0]); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_2, messagesToSend[0]); waitWrite(100); TestMsgHistoryService.controlDate1 = new Date(); logger.info("controlDate1:" + controlDate1.getTime()); waitWrite(100); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_1, messagesToSend[1]); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_2, messagesToSend[2]); waitWrite(100); TestMsgHistoryService.controlDate2 = new Date(); logger.info("controlDate2:" + controlDate2.getTime()); waitWrite(100); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_1, messagesToSend[3]); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_2, messagesToSend[4]); } /** * tests all read methods (finders) */ public void readRecords() { /** * This matches all written messages, they are minimum 3 */ Collection<EventObject> rs = msgHistoryService.findByKeyword(testMetaContact, "test"); assertTrue("Nothing found findByKeyword ", !rs.isEmpty()); List<String> msgs = getMessages(rs); assertTrue("Messages too few - findByKeyword", msgs.size() >= 3); /** * Will test case sensitive and insensitive search */ rs = msgHistoryService.findByKeyword(testMetaContact, "Test", false); assertTrue( "Nothing found findByKeyword caseINsensitive search", !rs.isEmpty()); msgs = getMessages(rs); assertTrue("Messages too few - findByKeyword", msgs.size() >= 3); rs = msgHistoryService.findByKeyword(testMetaContact, "Test", true); assertFalse( "Something found by findByKeyword casesensitive search", !rs.isEmpty()); /** * This must match also many messages, as tests are run many times * but the minimum is 3 */ rs = msgHistoryService.findByEndDate(testMetaContact, controlDate2); assertTrue("Nothing found findByEndDate", !rs.isEmpty()); msgs = getMessages(rs); assertTrue("Messages too few - findByEndDate", msgs.size() >= 3); /** * This must find also many messages but atleast one */ rs = msgHistoryService.findByKeywords( testMetaContact, new String[]{"test", "word2"}); assertTrue("Nothing found findByKeywords", !rs.isEmpty()); msgs = getMessages(rs); assertTrue("Messages too few - findByKeywords", msgs.size() >= 1); /** * Nothing to be found */ rs = msgHistoryService.findByKeywords( testMetaContact, new String[]{"test1", "word2"}); assertFalse("Something found findByKeywords", !rs.isEmpty()); /** * must find 2 messages */ rs = msgHistoryService.findByPeriod( testMetaContact, controlDate1, controlDate2); assertFalse("Nothing found findByPeriod", rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 2", 2, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[1].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[2].getContent())); /** * must find 1 record */ rs = msgHistoryService.findByPeriod( testMetaContact, controlDate1, controlDate2, new String[]{"word2"}); assertTrue("Nothing found findByPeriod", !rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 1", 1, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[1].getContent())); /** * must find 2 records */ rs = msgHistoryService.findByStartDate(testMetaContact, controlDate2); assertTrue("Nothing found findByStartDate", !rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 2", 2, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[3].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[4].getContent())); /** * Must return exactly the last 3 messages */ rs = msgHistoryService.findLast(testMetaContact, 3); assertTrue("Nothing found 8", !rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 3", 3, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[2].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[3].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[4].getContent())); /** * Must return exactly the 3 messages after controlDate1 */ rs = msgHistoryService.findFirstMessagesAfter(testMetaContact, controlDate1, 3); assertTrue("Nothing found 9", !rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 3", 3, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[1].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[2].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[3].getContent())); /** * Must return exactly the 3 messages before controlDate2 */ rs = msgHistoryService.findLastMessagesBefore(testMetaContact, controlDate2, 3); assertTrue("Nothing found 10", !rs.isEmpty()); msgs = getMessages(rs); assertEquals("Messages must be 3", 3, msgs.size()); assertTrue("Message no found", msgs.contains(messagesToSend[0].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[1].getContent())); assertTrue("Message no found", msgs.contains(messagesToSend[2].getContent())); } /** * Tests some special chars insert and read. */ public void specialChars() { mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_1, messagesToSend[5]); waitWrite(500); mockBImOpSet.deliverMessage(TEST_CONTACT_NAME_1, messagesToSend[6]); waitWrite(500); // Must return exactly the last 2 messages Collection<EventObject> rs = msgHistoryService.findLast(testMetaContact, 2); List<String> msgs = getMessages(rs); assertEquals("Sent messages must be available", 2, msgs.size()); // For now we are stripping in history the special content chars // in order to avoid breaking the history records in the xml assertTrue("Message " + messagesToSend[5].getContent() + " not found", msgs.contains(XmlEscapers.xmlContentEscaper().escape( messagesToSend[5].getContent()))); assertTrue("Message " + messagesToSend[6].getContent() + " not found", msgs.contains(messagesToSend[6].getContent())); } /** * Inserts a message between the control dates and queries to check * of the expected number of messages. */ public void insertRecords() { if(!(msgHistoryService instanceof MessageHistoryAdvancedService)) return; ((MessageHistoryAdvancedService)msgHistoryService).insertMessage( "out", null, testContact, messagesToSend[1], new Date(controlDate1.getTime() + 50), false); Collection<EventObject> rs = msgHistoryService.findByPeriod( testMetaContact, controlDate1, controlDate2); List<String> msgs = getMessages(rs); assertEquals("Messages must be found", 3, msgs.size()); } private static void waitWrite(long timeout) { synchronized (lock) { // wait a moment try { lock.wait(timeout); } catch (InterruptedException ex) { } } } private List<String> getMessages(Collection<EventObject> rs) { List<String> result = new Vector<String>(); for (EventObject item : rs) { if(item instanceof MessageDeliveredEvent) result.add( ((MessageDeliveredEvent)item) .getSourceMessage().getContent()); else if(item instanceof MessageReceivedEvent) result.add( ((MessageReceivedEvent)item) .getSourceMessage().getContent()); } return result; } private List<String> getChatMessages(Collection<EventObject> rs) { List<String> result = new Vector<String>(); for (EventObject item : rs) { if(item instanceof ChatRoomMessageDeliveredEvent) result.add(((ChatRoomMessageDeliveredEvent)item). getMessage().getContent()); else if(item instanceof ChatRoomMessageReceivedEvent) result.add(((ChatRoomMessageReceivedEvent)item). getMessage().getContent()); } return result; } // private void dumpResult(QueryResultSet rs) // { // while (rs.hasNext()) // { // HistoryRecord hr = (HistoryRecord)rs.next(); // logger.info("----------------------"); // // for (int i = 0; i < hr.getPropertyNames().length; i++) // { // logger.info(hr.getPropertyNames()[i] + " => " + hr.getPropertyValues()[i]); // } // // logger.info("----------------------"); // } // } }