Write tests for AsyncUnregister and TaskCloser

This commit is contained in:
ljacqu 2016-08-27 21:26:15 +02:00
parent afd4498184
commit f59a584622
4 changed files with 336 additions and 1 deletions

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.initialization;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.datasource.DataSource;
import org.bukkit.scheduler.BukkitScheduler;
@ -50,7 +51,7 @@ public class TaskCloser implements Runnable {
}
try {
Thread.sleep(1000);
sleep();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
break;
@ -73,6 +74,12 @@ public class TaskCloser implements Runnable {
}
}
/** Makes the current thread sleep for one second. */
@VisibleForTesting
void sleep() throws InterruptedException {
Thread.sleep(1000);
}
private List<Integer> getPendingTasks() {
List<Integer> pendingTasks = new ArrayList<>();
//returns only the async tasks

View File

@ -96,6 +96,8 @@ public class AsynchronousUnregister implements AsynchronousProcess {
ConsoleLogger.info(name + " was unregistered by " + initiator.getName());
service.send(initiator, MessageKey.UNREGISTERED_SUCCESS);
}
} else if (initiator != null) {
service.send(initiator, MessageKey.ERROR);
}
}

View File

@ -0,0 +1,155 @@
package fr.xephi.authme.initialization;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.datasource.DataSource;
import org.bukkit.Server;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLogger;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitWorker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Test for {@link TaskCloser}.
*/
@RunWith(MockitoJUnitRunner.class)
public class TaskCloserTest {
private static final int[] ACTIVE_WORKERS_ID = {2, 5};
private TaskCloser taskCloser;
@Mock
private AuthMe authMe;
@Mock
private PluginLogger logger;
@Mock
private BukkitScheduler bukkitScheduler;
@Mock
private DataSource dataSource;
@Before
public void initAuthMe() {
Server server = mock(Server.class);
given(server.getScheduler()).willReturn(bukkitScheduler);
ReflectionTestUtils.setField(JavaPlugin.class, authMe, "server", server);
ReflectionTestUtils.setField(JavaPlugin.class, authMe, "logger", logger);
taskCloser = spy(new TaskCloser(authMe, dataSource));
}
@Test
public void shouldWaitForTasksToClose() throws InterruptedException {
// given
doNothing().when(taskCloser).sleep(); // avoid sleeping in tests
mockActiveWorkers();
given(bukkitScheduler.isCurrentlyRunning(ACTIVE_WORKERS_ID[0])).willReturn(false);
given(bukkitScheduler.isCurrentlyRunning(ACTIVE_WORKERS_ID[1]))
.willReturn(true) // first time
.willReturn(false); // second time
// when
taskCloser.run();
// then
verify(bukkitScheduler, times(3)).isQueued(anyInt());
ArgumentCaptor<Integer> taskIds = ArgumentCaptor.forClass(Integer.class);
verify(bukkitScheduler, times(3)).isCurrentlyRunning(taskIds.capture());
assertThat(taskIds.getAllValues(), contains(ACTIVE_WORKERS_ID[0], ACTIVE_WORKERS_ID[1], ACTIVE_WORKERS_ID[1]));
verify(taskCloser, times(2)).sleep();
verify(dataSource).close();
}
@Test
public void shouldAbortForNeverEndingTask() throws InterruptedException {
// given
doNothing().when(taskCloser).sleep(); // avoid sleeping in tests
mockActiveWorkers();
// This task never ends
given(bukkitScheduler.isCurrentlyRunning(ACTIVE_WORKERS_ID[0])).willReturn(true);
given(bukkitScheduler.isCurrentlyRunning(ACTIVE_WORKERS_ID[1])).willReturn(false);
// when
taskCloser.run();
// then
verify(bukkitScheduler, times(3)).isQueued(anyInt());
verify(bukkitScheduler, times(61)).isCurrentlyRunning(anyInt());
verify(taskCloser, times(60)).sleep();
verify(dataSource).close();
}
@Test
public void shouldStopForInterruptedThread() throws InterruptedException, ExecutionException {
// Note ljacqu 20160827: This test must be run in its own thread because we throw an InterruptedException.
// Somehow the java.nio.Files API used in tests that are run subsequently don't like this and fail otherwise.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
@Override
public void run() {
try {
shouldStopForInterruptedThread0();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}).get();
}
/** Test implementation for {@link #shouldStopForInterruptedThread()}. */
private void shouldStopForInterruptedThread0() throws InterruptedException {
// given
taskCloser = spy(new TaskCloser(authMe, null));
// First two times do nothing, third time throw exception when we sleep
doNothing().doNothing().doThrow(InterruptedException.class).when(taskCloser).sleep();
mockActiveWorkers();
given(bukkitScheduler.isCurrentlyRunning(anyInt())).willReturn(true);
// when
taskCloser.run();
// then
verify(bukkitScheduler, times(4)).isCurrentlyRunning(anyInt());
verify(taskCloser, times(3)).sleep();
}
private void mockActiveWorkers() {
Plugin otherOwner = mock(Plugin.class);
List<BukkitWorker> tasks = Arrays.asList(
mockBukkitWorker(authMe, ACTIVE_WORKERS_ID[0], false),
mockBukkitWorker(otherOwner, 3, false),
mockBukkitWorker(authMe, ACTIVE_WORKERS_ID[1], false),
mockBukkitWorker(authMe, 7, true),
mockBukkitWorker(otherOwner, 11, true));
given(bukkitScheduler.getActiveWorkers()).willReturn(tasks);
}
private BukkitWorker mockBukkitWorker(Plugin owner, int taskId, boolean isQueued) {
BukkitWorker worker = mock(BukkitWorker.class);
given(worker.getOwner()).willReturn(owner);
given(worker.getTaskId()).willReturn(taskId);
given(bukkitScheduler.isQueued(taskId)).willReturn(isQueued);
return worker;
}
}

View File

@ -16,6 +16,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.task.PlayerDataTaskManager;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.TeleportationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.junit.BeforeClass;
import org.junit.Test;
@ -27,6 +28,7 @@ import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@ -118,4 +120,173 @@ public class AsynchronousUnregisterTest {
verify(bukkitService).runTask(any(Runnable.class));
}
@Test
public void shouldPerformUnregisterAndNotApplyBlindEffect() {
// given
Player player = mock(Player.class);
String name = "Frank21";
given(player.getName()).willReturn(name);
given(player.isOnline()).willReturn(true);
PlayerAuth auth = mock(PlayerAuth.class);
given(playerCache.getAuth(name)).willReturn(auth);
HashedPassword password = new HashedPassword("password", "in_auth_obj");
given(auth.getPassword()).willReturn(password);
String userPassword = "pass";
given(passwordSecurity.comparePassword(userPassword, password, name)).willReturn(true);
given(dataSource.removeAuth(name)).willReturn(true);
given(service.getProperty(RegistrationSettings.FORCE)).willReturn(true);
given(service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)).willReturn(true);
given(service.getProperty(RestrictionSettings.TIMEOUT)).willReturn(0);
// when
asynchronousUnregister.unregister(player, userPassword);
// then
verify(service).send(player, MessageKey.UNREGISTERED_SUCCESS);
verify(passwordSecurity).comparePassword(userPassword, password, name);
verify(dataSource).removeAuth(name);
verify(playerCache).removePlayer(name);
verify(teleportationService).teleportOnJoin(player);
verify(authGroupHandler).setGroup(player, AuthGroupType.UNREGISTERED);
verify(bukkitService).runTask(any(Runnable.class));
}
@Test
public void shouldNotApplyUnregisteredEffectsForNotForcedRegistration() {
// given
Player player = mock(Player.class);
String name = "__FranK";
given(player.getName()).willReturn(name);
given(player.isOnline()).willReturn(true);
String userPassword = "141$$5ad";
HashedPassword password = new HashedPassword("ttt123");
PlayerAuth auth = PlayerAuth.builder().name(name).password(password).build();
given(playerCache.getAuth(name)).willReturn(auth);
given(passwordSecurity.comparePassword(userPassword, password, name)).willReturn(true);
given(dataSource.removeAuth(name)).willReturn(true);
given(service.getProperty(RegistrationSettings.FORCE)).willReturn(false);
// when
asynchronousUnregister.unregister(player, userPassword);
// then
verify(service).send(player, MessageKey.UNREGISTERED_SUCCESS);
verify(passwordSecurity).comparePassword(userPassword, password, name);
verify(dataSource).removeAuth(name);
verify(playerCache).removePlayer(name);
verify(authGroupHandler).setGroup(player, AuthGroupType.UNREGISTERED);
verifyZeroInteractions(teleportationService, playerDataTaskManager);
verify(bukkitService, never()).runTask(any(Runnable.class));
}
@Test
public void shouldHandleDatabaseError() {
// given
Player player = mock(Player.class);
String name = "Frank21";
given(player.getName()).willReturn(name);
given(player.isOnline()).willReturn(true);
PlayerAuth auth = mock(PlayerAuth.class);
given(playerCache.getAuth(name)).willReturn(auth);
HashedPassword password = new HashedPassword("password", "in_auth_obj");
given(auth.getPassword()).willReturn(password);
String userPassword = "pass";
given(passwordSecurity.comparePassword(userPassword, password, name)).willReturn(true);
given(dataSource.removeAuth(name)).willReturn(false);
// when
asynchronousUnregister.unregister(player, userPassword);
// then
verify(passwordSecurity).comparePassword(userPassword, password, name);
verify(dataSource).removeAuth(name);
verify(service).send(player, MessageKey.ERROR);
verifyZeroInteractions(teleportationService, authGroupHandler, bukkitService);
}
@Test
public void shouldNotTeleportOfflinePlayer() {
// given
Player player = mock(Player.class);
String name = "Frank21";
given(player.getName()).willReturn(name);
given(player.isOnline()).willReturn(false);
PlayerAuth auth = mock(PlayerAuth.class);
given(playerCache.getAuth(name)).willReturn(auth);
HashedPassword password = new HashedPassword("password", "in_auth_obj");
given(auth.getPassword()).willReturn(password);
String userPassword = "pass";
given(passwordSecurity.comparePassword(userPassword, password, name)).willReturn(true);
given(dataSource.removeAuth(name)).willReturn(true);
given(service.getProperty(RegistrationSettings.FORCE)).willReturn(true);
given(service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)).willReturn(true);
given(service.getProperty(RestrictionSettings.TIMEOUT)).willReturn(12);
// when
asynchronousUnregister.unregister(player, userPassword);
// then
verify(passwordSecurity).comparePassword(userPassword, password, name);
verify(dataSource).removeAuth(name);
verify(playerCache).removePlayer(name);
verifyZeroInteractions(teleportationService, authGroupHandler);
}
// Initiator known and Player object available
@Test
public void shouldPerformAdminUnregister() {
// given
Player player = mock(Player.class);
String name = "Frank21";
given(player.getName()).willReturn(name);
given(player.isOnline()).willReturn(true);
given(dataSource.removeAuth(name)).willReturn(true);
given(service.getProperty(RegistrationSettings.FORCE)).willReturn(true);
given(service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)).willReturn(true);
given(service.getProperty(RestrictionSettings.TIMEOUT)).willReturn(12);
CommandSender initiator = mock(CommandSender.class);
// when
asynchronousUnregister.adminUnregister(initiator, name, player);
// then
verify(service).send(player, MessageKey.UNREGISTERED_SUCCESS);
verify(service).send(initiator, MessageKey.UNREGISTERED_SUCCESS);
verify(dataSource).removeAuth(name);
verify(playerCache).removePlayer(name);
verify(teleportationService).teleportOnJoin(player);
verify(authGroupHandler).setGroup(player, AuthGroupType.UNREGISTERED);
verify(bukkitService).runTask(any(Runnable.class));
}
@Test
public void shouldPerformAdminUnregisterWithoutInitiatorOrPlayer() {
// given
String name = "billy";
given(dataSource.removeAuth(name)).willReturn(true);
// when
asynchronousUnregister.adminUnregister(null, name, null);
// then
verify(dataSource).removeAuth(name);
verify(playerCache).removePlayer(name);
verifyZeroInteractions(authGroupHandler, teleportationService);
}
@Test
public void shouldHandleDatabaseErrorForAdminUnregister() {
// given
String name = "TtOoLl";
CommandSender initiator = mock(CommandSender.class);
given(dataSource.removeAuth(name)).willReturn(false);
// when
asynchronousUnregister.adminUnregister(initiator, name, null);
// then
verify(dataSource).removeAuth(name);
verify(service).send(initiator, MessageKey.ERROR);
verifyZeroInteractions(playerCache, teleportationService, authGroupHandler);
}
}