/*
* Copyright 2000-2006 JetBrains s.r.o.
*
* 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 jetbrains.communicator.p2p;
import jetbrains.communicator.core.impl.BaseTestCase;
import jetbrains.communicator.core.Pico;
import jetbrains.communicator.core.impl.dispatcher.AsyncMessageDispatcherImpl;
import jetbrains.communicator.core.impl.users.UserImpl;
import jetbrains.communicator.core.impl.users.UserModelImpl;
import jetbrains.communicator.core.users.*;
import jetbrains.communicator.ide.NullProgressIndicator;
import jetbrains.communicator.mock.MockIDEFacade;
import jetbrains.communicator.mock.MockTransport;
import jetbrains.communicator.mock.MockUser;
import jetbrains.communicator.p2p.commands.AddOnlineUserP2PCommand;
import jetbrains.communicator.util.StringUtil;
import jetbrains.communicator.util.WaitFor;
import org.picocontainer.MutablePicoContainer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Vector;
/**
* @author Kir Maximov
*
*/
public class P2PTransportTest extends BaseTestCase {
private P2PTransport myTransport;
private String myLog;
private MockIDEFacade myIdeFacade;
private UserModelImpl myUserModel;
public static final String PROJECT_NAME = "project234";
public static final int WAIT_USER_RESPONSES_TIMEOUT = 500;
protected AsyncMessageDispatcherImpl myDispatcher;
private MutablePicoContainer myProjectLevelContainer;
public P2PTransportTest(String s) {
super(s);
}
@Override
protected void setUp() throws Exception {
super.setUp();
myUserModel = new UserModelImpl(getBroadcaster());
disposeOnTearDown(myUserModel);
myIdeFacade = new MockIDEFacade(getClass());
myIdeFacade.setReturnedProjects(new String[]{PROJECT_NAME});
myDispatcher = new AsyncMessageDispatcherImpl(getBroadcaster(), myIdeFacade);
disposeOnTearDown(myDispatcher);
myTransport = new P2PTransport(myDispatcher, myUserModel, WAIT_USER_RESPONSES_TIMEOUT) {
@Override
protected void sendUserAddedCallback(User user) {
super.sendUserAddedCallback(user);
myLog += "sendUserAddedCallback" + user;
}
};
Pico.getInstance().registerComponentInstance(myTransport);
myLog = "";
myProjectLevelContainer = Pico.getInstance().makeChildContainer();
}
@Override
protected void tearDown() throws Exception {
if (myTransport != null) {
myTransport.dispose();
Pico.getInstance().unregisterComponentByInstance(myTransport);
}
StringUtil.setMyUsername(null);
super.tearDown();
}
public void testFindUsers() throws Exception {
User[] users = myTransport.findUsers(new NullProgressIndicator());
assertTrue("At least self should be found", users.length >= 1);
User self = null;
for (User user : users) {
if (user.getName().equals(StringUtil.getMyUsername())) {
self = user;
break;
}
}
assertNotNull("Self user not found in " + Arrays.asList(users), self);
assertTrue("Self should be online", self.isOnline());
InetAddress address = myTransport.getAddress(self);
assertTrue("Self address is expected:" + address, NetworkUtil.isOwnAddress(address));
assertEquals("Projects should be set", PROJECT_NAME, self.getProjects()[0]);
}
public void testSetOwnPresence() throws Exception {
registerResponseProviders(myUserModel, myIdeFacade);
// Add self to contact list
User self = myUserModel.createUser(StringUtil.getMyUsername(), myTransport.getName());
myUserModel.addUser(self);
// Wait for next cycle of user finding
new WaitFor(1000) { @Override
protected boolean condition() { return !myTransport.getUserMonitorThread().isFinding(); } };
// make self away
UserPresence presence = new UserPresence(PresenceMode.AWAY);
assert presence.isOnline();
myTransport.setOwnPresence(presence);
// make sure that away status will be updated
myTransport.findUsers(new NullProgressIndicator());
assert PresenceMode.AWAY == self.getPresence().getPresenceMode();
// Now, test itself. We go online and want this status to be updated almost immediately.
myEvents.clear();
addEventListener();
myTransport.setOwnPresence(new UserPresence(PresenceMode.AVAILABLE));
final User self1 = self;
new WaitFor(200) {
@Override
protected boolean condition() {
return self1.getPresence().getPresenceMode() == PresenceMode.AVAILABLE;
}
};
assertSame("Should provide correct presence mode", PresenceMode.AVAILABLE,
myTransport.getUserPresence(self).getPresenceMode());
UserEvent.Updated event = (UserEvent.Updated) checkEvent(true);
assertNotNull("Expect go online event", event);
assertEquals("presence", event.getPropertyName());
}
public void testInitialize_OurProject() throws Throwable {
initializeProject(PROJECT_NAME);
User[] users = myUserModel.getAllUsers();
assertTrue("At least self should be found/added", users.length > 0);
assertEquals("Project name should become group", PROJECT_NAME, users[0].getGroup());
assertEquals("One group expected", 1, myUserModel.getGroups().length);
}
private User createSelf() throws UnknownHostException {
return myTransport.createUser(StringUtil.getMyUsername(), new OnlineUserInfo(InetAddress.getLocalHost(), myTransport.getPort()));
}
public void testInitialize_ExistsInOtherGroup() throws Throwable {
User self = createSelf();
myUserModel.addUser(self);
myUserModel.addGroup(PROJECT_NAME);
self.setGroup("A group", myUserModel);
initializeProject(PROJECT_NAME);
User[] users = myUserModel.getAllUsers();
assertEquals("Group should be kept", "A group", users[0].getGroup());
}
private void initializeProject(String projectName) throws InterruptedException {
myTransport.initializeProject(projectName, myProjectLevelContainer);
Thread.sleep(WAIT_USER_RESPONSES_TIMEOUT *5);
}
public void testInitialize_WrongProject() throws Throwable {
initializeProject("Bad_project");
User[] users = myUserModel.getAllUsers();
assertEquals("No one from Bad_project should be found/added", 0, users.length);
assertEquals("No groups should be added", 0, myUserModel.getGroups().length);
}
public void testCanAddUsers() throws Throwable {
myUserModel.addGroup("Fabrique");
assertFalse("No users", myTransport.canAddUsers("project", new HashSet<User>()));
assertTrue("Group already exists - can add new users", myTransport.canAddUsers("Fabrique", Arrays.asList(user("foo"), user("bar"))));
assertTrue("Group not exists - new users to new project",
myTransport.canAddUsers("IDEA", Arrays.asList(user("foo"), user("bar"))));
User user = user("foo");
myUserModel.addUser(user);
user.setGroup(UserModel.DEFAULT_GROUP, myUserModel);
assertFalse("Already has added user",
myTransport.canAddUsers("IDEA", Arrays.asList(user("foo"), user("bar"))));
}
private User user(String s) {
return new MockUser(s, null);
}
public void testIsOnline() throws Exception {
User mockUser = myTransport.createUser("mock", new OnlineUserInfo(InetAddress.getLocalHost(), myTransport.getPort()));
assertFalse(mockUser.isOnline());
myTransport.setOnlineUsers(Arrays.asList(mockUser));
assertTrue("should be online now", mockUser.isOnline());
assertTrue(UserImpl.create("mock", P2PTransport.CODE).isOnline());
}
public void testGetAddress() throws Exception {
User mockUser = UserImpl.create("mock", P2PTransport.CODE);
assertNull("Sanity check", myTransport.getAddress(mockUser));
new AddOnlineUserP2PCommand(myTransport.getUserMonitorThread())
.addOnlineUser("localhost", "mock", 3354, null, null);
myTransport.flushCurrentUsers();
assertEquals("Inet address should be set from available online user",
"localhost", myTransport.getAddress(mockUser).getHostName());
myTransport.setOnlineUsers(new HashSet<User>());
assertNull("Inet address should be reset", myTransport.getAddress(mockUser));
}
public void testGetProjects() throws Exception {
User mockUser = UserImpl.create("mock", P2PTransport.CODE);
assertEquals("Sanity check", 0, myTransport.getProjects(mockUser).length);
Vector<String> projects = new Vector<String>(Arrays.asList("project1", "project2"));
new AddOnlineUserP2PCommand(myTransport.getUserMonitorThread())
.addOnlineUser("localhost", "mock", 0, projects, null);
myTransport.flushCurrentUsers();
assertEquals("Projects should be set from available online user",
projects.toString(), Arrays.asList(myTransport.getProjects(mockUser)).toString());
myTransport.setOnlineUsers(new HashSet<User>());
assertEquals("Projects should be reset", 0, myTransport.getProjects(mockUser).length);
}
public void testGetPort() throws Exception {
User mockUser = UserImpl.create("mock", P2PTransport.CODE);
assertEquals("Sanity check", -1, myTransport.getPort(mockUser));
new AddOnlineUserP2PCommand(myTransport.getUserMonitorThread())
.addOnlineUser("localhost", "mock", 3354, null, null);
myTransport.flushCurrentUsers();
assertEquals("Port should be set from available online user",
3354, myTransport.getPort(mockUser));
myTransport.setOnlineUsers(new HashSet<User>());
assertEquals("Port should be reset", -1, myTransport.getPort(mockUser));
}
public void testGetUserPresence() throws Exception {
User mockUser = UserImpl.create("mock", P2PTransport.CODE);
assertEquals("Sanity check", PresenceMode.UNAVAILABLE, myTransport.getUserPresence(mockUser).getPresenceMode());
new AddOnlineUserP2PCommand(myTransport.getUserMonitorThread())
.addOnlineUser("localhost", "mock", 3354, null, new UserPresence(PresenceMode.DND).toVector());
myTransport.flushCurrentUsers();
assertEquals("User status should be set from available online user",
PresenceMode.DND, myTransport.getUserPresence(mockUser).getPresenceMode());
myTransport.setOnlineUsers(new HashSet<User>());
assertEquals("Presence should be reset", PresenceMode.UNAVAILABLE, myTransport.getUserPresence(mockUser).getPresenceMode());
}
public void testOnUserAdd() throws Exception {
User mockUser = UserImpl.create("user", myTransport.getName());
getBroadcaster().fireEvent(new UserEvent.Added(mockUser));
assertEquals("Should send notification", "sendUserAddedCallback" + mockUser, myLog);
}
public void testOnUserAdd_AnotherTransport() throws Exception {
User mockUser = UserImpl.create("user", MockTransport.NAME);
getBroadcaster().fireEvent(new UserEvent.Added(mockUser));
assertEquals("Should not send notification for another transport:" + myLog, "", myLog);
}
public void testSetOnlineUsers_UpdateEvent() throws Exception {
myTransport.setOnlineUsers(new HashSet<User>());
User user = myTransport.createUser("someUser", new OnlineUserInfo(null, 0, null, new UserPresence(PresenceMode.AWAY)));
myTransport.setOnlineUsers(Collections.singleton(user));
addEventListener();
user = myTransport.createUser("someUser", new OnlineUserInfo(null, 0, null, new UserPresence(PresenceMode.AWAY)));
myTransport.setOnlineUsers(Collections.singleton(user));
assertEquals("Same user data, no events expected: " + myEvents, 0, myEvents.size());
user = myTransport.createUser("someUser", new OnlineUserInfo(null, 0, null, new UserPresence(PresenceMode.EXTENDED_AWAY)));
myTransport.setOnlineUsers(Collections.singleton(user));
UserEvent.Updated event = (UserEvent.Updated) checkEvent(true);
assertEquals("Precense changed: " + myEvents, "presence", event.getPropertyName());
}
public void testSetOnlineUsers_OnlineEvent() throws Exception {
addEventListener();
// Set none users
myTransport.setOnlineUsers(new HashSet<User>());
assertEquals("No online users, no change expected", 0, myEvents.size());
// Got one online user
User bill = myTransport.createUser("bill", new OnlineUserInfo(InetAddress.getLocalHost(), myTransport.getPort()));
myEvents.clear();
myTransport.setOnlineUsers(Arrays.asList(bill));
assertEquals("Online status for bill should have changed:" + myEvents, 1, myEvents.size());
checkEvent(bill, 0, true);
myEvents.clear();
User john = myTransport.createUser("john", new OnlineUserInfo(InetAddress.getLocalHost(), myTransport.getPort()));
myTransport.setOnlineUsers(Arrays.asList(john));
assertTrue(john.isOnline());
assertTrue(john.getPresence().isOnline());
assertFalse(bill.isOnline());
assertEquals("Online status for bill and john should have changed: " + myEvents, 2, myEvents.size());
checkEvent(bill, 0, false);
checkEvent(john, 1, true);
myEvents.clear();
myTransport.setOnlineUsers(Arrays.asList(myTransport.createUser("john", new OnlineUserInfo(InetAddress.getLocalHost(), myTransport.getPort()))));
assertEquals("Online status didn't change - no events expected: " + myEvents, 0, myEvents.size());
assertEquals("Address should have changed", InetAddress.getLocalHost(), myTransport.getAddress(john));
}
private void checkEvent(User affectedUser, int eventId, boolean becomeOnline) {
assertEquals(affectedUser, evt(eventId).getUser());
assertEquals("online", evt(eventId).getPropertyName());
assertEquals(!becomeOnline, ((Boolean) evt(eventId).getOldValue()).booleanValue());
assertEquals(becomeOnline, ((Boolean) evt(eventId).getNewValue()).booleanValue());
}
private UserEvent.Updated evt(int i) {
return (UserEvent.Updated) myEvents.get(i);
}
}