Added purge protection command and test class for purge.

Note that game mode addons must add the purge command before it can be
used.

https://github.com/BentoBoxWorld/BentoBox/issues/836
This commit is contained in:
tastybento 2019-07-11 22:50:32 -07:00
parent a30fc4b102
commit 9422f8ac3d
6 changed files with 431 additions and 23 deletions

View File

@ -39,10 +39,11 @@ public class AdminPurgeCommand extends CompositeCommand implements Listener {
setDescription("commands.admin.purge.description");
new AdminPurgeStopCommand(this);
new AdminPurgeUnownedCommand(this);
new AdminPurgeProtectCommand(this);
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean canExecute(User user, String label, List<String> args) {
if (inPurge) {
user.sendMessage("commands.admin.purge.purge-in-progress");
return false;
@ -52,6 +53,11 @@ public class AdminPurgeCommand extends CompositeCommand implements Listener {
showHelp(this, user);
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.get(0).equalsIgnoreCase("confirm") && toBeConfirmed && this.user.equals(user)) {
removeIslands();
return true;
@ -105,29 +111,14 @@ public class AdminPurgeCommand extends CompositeCommand implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
void onIslandDeleted(IslandDeletedEvent e) {
if (inPurge && it.hasNext()) {
getIslands().getIslandById(it.next()).ifPresent(i -> {
getIslands().deleteIsland(i, true, null);
count++;
getPlugin().log(count + " islands purged");
});
} else {
user.sendMessage("commands.admin.purge.completed");
inPurge = false;
if (inPurge) {
deleteIsland();
}
}
Set<String> getUnownedIslands() {
return getPlugin().getIslands().getIslands().stream()
.filter(i -> i.getWorld().equals(this.getWorld()))
.filter(i -> i.getOwner() == null)
.map(Island::getUniqueId)
.collect(Collectors.toSet());
}
Set<String> getOldIslands(int days) {
return getPlugin().getIslands().getIslands().stream()
.filter(i -> !i.getPurgeProtected())
.filter(i -> i.getWorld().equals(this.getWorld()))
.filter(i -> i.getOwner() != null)
.filter(i -> i.getMembers().size() == 1)
@ -153,14 +144,14 @@ public class AdminPurgeCommand extends CompositeCommand implements Listener {
/**
* @param user the user to set
*/
public void setUser(User user) {
void setUser(User user) {
this.user = user;
}
/**
* @param islands the islands to set
*/
public void setIslands(Set<String> islands) {
void setIslands(Set<String> islands) {
this.islands = islands;
}
}

View File

@ -0,0 +1,53 @@
package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminPurgeProtectCommand extends CompositeCommand {
private Island island;
public AdminPurgeProtectCommand(CompositeCommand parent) {
super(parent, "protect");
}
@Override
public void setup() {
setPermission("admin.purge");
setOnlyPlayer(true);
setDescription("commands.admin.purge.protect.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
// Get island where the player is
if (!getIslands().getIslandAt(user.getLocation()).map(i -> {
island = i;
return true;
}).orElse(false)) {
user.sendMessage("commands.admin.purge.protect.move-to-island");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
island.setPurgeProtected(!island.getPurgeProtected());
if (island.getPurgeProtected()) {
user.sendMessage("commands.admin.purge.protect.protecting");
} else {
user.sendMessage("commands.admin.purge.protect.unprotecting");
}
return true;
}
}

View File

@ -2,10 +2,12 @@ package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminPurgeUnownedCommand extends ConfirmableCommand {
@ -33,7 +35,7 @@ public class AdminPurgeUnownedCommand extends ConfirmableCommand {
user.sendMessage("commands.admin.purge.purge-in-progress");
return false;
}
Set<String> unowned = parentCommand.getUnownedIslands();
Set<String> unowned = getUnownedIslands();
user.sendMessage("commands.admin.purge.unowned.unowned-islands", TextVariables.NUMBER, String.valueOf(unowned.size()));
if (!unowned.isEmpty()) {
this.askConfirmation(user, () -> {
@ -44,4 +46,15 @@ public class AdminPurgeUnownedCommand extends ConfirmableCommand {
}
return true;
}
Set<String> getUnownedIslands() {
return getPlugin().getIslands().getIslands().stream()
.filter(i -> !i.getPurgeProtected())
.filter(i -> i.getWorld().equals(this.getWorld()))
.filter(i -> i.getOwner() == null)
.map(Island::getUniqueId)
.collect(Collectors.toSet());
}
}

View File

@ -911,6 +911,9 @@ public class Island implements DataObject {
user.sendMessage("commands.admin.info.banned-players");
banned.forEach(u -> user.sendMessage("commands.admin.info.banned-format", TextVariables.NAME, plugin.getPlayers().getName(u)));
}
if (purgeProtected) {
user.sendMessage("commands.admin.info.purge-protected");
}
return true;
}

View File

@ -66,7 +66,12 @@ commands:
number-error: "&cArgument must be a number of days"
confirm: "&dType [label] purge confirm to start purging"
completed: "&aPurging stopped"
see-console-for-status: "Purge started. See console for status"
see-console-for-status: "Purge started. See console for status"
protect:
description: "Toggle island purge protection"
move-to-island: "&cMove to an island first!"
protecting: "&aPurge-protecting island"
unprotecting: "&aRemoving purge protection"
stop:
description: "Stop a purge in progress"
stopping: "Stopping the purge"
@ -154,6 +159,7 @@ commands:
island-coords: "Island coordinates: [xz1] to [xz2]"
islands-in-trash: "&dPlayer has islands in trash."
protection-range: "Protection range: [range]"
purge-protected: "Island is purge protected"
max-protection-range: "Largest historical protection range: [range]"
protection-coords: "Protection coordinates: [xz1] to [xz2]"
is-spawn: "Island is a spawn island"

View File

@ -0,0 +1,342 @@
/**
*
*/
package world.bentobox.bentobox.api.commands.admin.purge;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeletedEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.RanksManager;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, User.class })
public class AdminPurgeCommandTest {
@Mock
private BentoBox plugin;
@Mock
private CompositeCommand ac;
@Mock
private User user;
@Mock
private IslandsManager im;
private AdminPurgeCommand apc;
@Mock
private Addon addon;
@Mock
private Island island;
@Mock
private World world;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
when(ac.getWorld()).thenReturn(world);
when(ac.getAddon()).thenReturn(addon);
when(ac.getTopLabel()).thenReturn("bsb");
// Island manager
when(plugin.getIslands()).thenReturn(im);
// No islands by default
when(im.getIslands()).thenReturn(Collections.emptyList());
// IWM
IslandWorldManager iwm = mock(IslandWorldManager.class);
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(plugin.getIWM()).thenReturn(iwm);
// Command
apc = new AdminPurgeCommand(ac);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#AdminPurgeCommand(CompositeCommand)}.
*/
@Test
public void testConstructor() {
verify(addon).registerListener(apc);
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#setup()}.
*/
@Test
public void testSetup() {
assertEquals("admin.purge", apc.getPermission());
assertFalse(apc.isOnlyPlayer());
assertEquals("commands.admin.purge.parameters", apc.getParameters());
assertEquals("commands.admin.purge.description", apc.getDescription());
assertEquals(4, apc.getSubCommands().size());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteUserStringListOfStringEmptyArgs() {
assertFalse(apc.canExecute(user, "protect", Collections.emptyList()));
verify(user).sendMessage("commands.help.header",
"[label]",
"BSkyBlock");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteUserStringListOfStringWithArg() {
assertTrue(apc.canExecute(user, "protect", Collections.singletonList("23")));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNotNumber() {
assertFalse(apc.execute(user, "protect", Collections.singletonList("abc")));
verify(user).sendMessage(eq("commands.admin.purge.number-error"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringZero() {
assertFalse(apc.execute(user, "protect", Collections.singletonList("0")));
verify(user).sendMessage(eq("commands.admin.purge.days-one-or-more"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslands() {
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslandsPurgeProtected() {
when(island.getPurgeProtected()).thenReturn(true);
when(im.getIslands()).thenReturn(Collections.singleton(island));
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslandsWrongWorld() {
when(island.getPurgeProtected()).thenReturn(false);
when(island.getWorld()).thenReturn(mock(World.class));
when(im.getIslands()).thenReturn(Collections.singleton(island));
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslandsUnowned() {
when(island.getPurgeProtected()).thenReturn(false);
when(island.getWorld()).thenReturn(world);
when(island.getOwner()).thenReturn(null);
when(im.getIslands()).thenReturn(Collections.singleton(island));
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslandsTeamIsland() {
when(island.getPurgeProtected()).thenReturn(false);
when(island.getWorld()).thenReturn(world);
when(island.getOwner()).thenReturn(UUID.randomUUID());
Map<UUID, Integer> team = new HashMap<>();
team.put(UUID.randomUUID(), RanksManager.OWNER_RANK);
team.put(UUID.randomUUID(), RanksManager.MEMBER_RANK);
when(island.getMembers()).thenReturn(team);
when(im.getIslands()).thenReturn(Collections.singleton(island));
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoIslandsRecentLogin() {
when(island.getPurgeProtected()).thenReturn(false);
when(island.getWorld()).thenReturn(world);
when(island.getOwner()).thenReturn(UUID.randomUUID());
Map<UUID, Integer> team = new HashMap<>();
team.put(UUID.randomUUID(), RanksManager.OWNER_RANK);
when(island.getMembers()).thenReturn(team);
when(im.getIslands()).thenReturn(Collections.singleton(island));
PowerMockito.mockStatic(Bukkit.class);
OfflinePlayer op = mock(OfflinePlayer.class);
when(op.getLastPlayed()).thenReturn(System.currentTimeMillis());
when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(op);
assertTrue(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("0"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringIslandsFound() {
when(island.getPurgeProtected()).thenReturn(false);
when(island.getWorld()).thenReturn(world);
when(island.getOwner()).thenReturn(UUID.randomUUID());
Map<UUID, Integer> team = new HashMap<>();
team.put(UUID.randomUUID(), RanksManager.OWNER_RANK);
when(island.getMembers()).thenReturn(team);
when(im.getIslands()).thenReturn(Collections.singleton(island));
PowerMockito.mockStatic(Bukkit.class);
OfflinePlayer op = mock(OfflinePlayer.class);
when(op.getLastPlayed()).thenReturn(0L);
when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(op);
assertFalse(apc.execute(user, "protect", Collections.singletonList("10")));
verify(user).sendMessage(eq("commands.admin.purge.purgable-islands"), eq("[number]"), eq("1"));
verify(user).sendMessage(eq("commands.admin.purge.confirm"), eq("[label]"), eq("bsb"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#removeIslands()}.
*/
@Test
public void testRemoveIslands() {
@NonNull
Optional<Island> opIsland = Optional.of(island);
when(im.getIslandById(any())).thenReturn(opIsland);
testExecuteUserStringListOfStringIslandsFound();
assertTrue(apc.execute(user, "protect", Collections.singletonList("confirm")));
verify(im).deleteIsland(eq(island), eq(true), eq(null));
verify(plugin).log(eq("1 islands purged"));
verify(user).sendMessage(eq("commands.admin.purge.see-console-for-status"));
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#onIslandDeleted(world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeletedEvent)}.
*/
@Test
public void testOnIslandDeletedNotInPurge() {
IslandDeletedEvent e = mock(IslandDeletedEvent.class);
apc.onIslandDeleted(e);
verify(user, Mockito.never()).sendMessage(any());
verify(plugin, Mockito.never()).log(any());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#onIslandDeleted(world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeletedEvent)}.
*/
@Test
public void testOnIslandDeletedPurgeCompleted() {
testRemoveIslands();
IslandDeletedEvent e = mock(IslandDeletedEvent.class);
apc.onIslandDeleted(e);
verify(user).sendMessage(eq("commands.admin.purge.completed"));
verify(plugin, Mockito.never()).log("");
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#isInPurge()}.
*/
@Test
public void testIsInPurge() {
assertFalse(apc.isInPurge());
testRemoveIslands();
assertTrue(apc.isInPurge());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#stop()}.
*/
@Test
public void testStop() {
testRemoveIslands();
assertTrue(apc.isInPurge());
apc.stop();
assertFalse(apc.isInPurge());
}
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#setUser(world.bentobox.bentobox.api.user.User)}.
*/
@Test
public void testSetUser() {
apc.setUser(user);
apc.removeIslands();
verify(user, Mockito.times(2)).sendMessage(any());
}
}