mirror of
https://github.com/lucko/LuckPerms.git
synced 2025-08-22 06:02:49 +02:00
Implement paginated logs for all storage backends
This commit is contained in:
@@ -4,7 +4,11 @@ plugins {
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform {}
|
||||
useJUnitPlatform {
|
||||
if (!project.hasProperty('dockerTests')) {
|
||||
excludeTags 'docker'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jacocoTestReport {
|
||||
@@ -15,9 +19,14 @@ dependencies {
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1'
|
||||
testImplementation "org.testcontainers:junit-jupiter:1.19.8"
|
||||
testImplementation 'org.mockito:mockito-core:5.11.0'
|
||||
testImplementation 'org.mockito:mockito-junit-jupiter:5.11.0'
|
||||
testImplementation 'com.h2database:h2:2.1.214'
|
||||
testImplementation 'org.mongodb:mongodb-driver-legacy:4.5.0'
|
||||
testImplementation 'org.spongepowered:configurate-yaml:3.7.2'
|
||||
testImplementation 'org.spongepowered:configurate-hocon:3.7.2'
|
||||
testImplementation 'me.lucko.configurate:configurate-toml:3.7'
|
||||
|
||||
api project(':api')
|
||||
api 'org.checkerframework:checker-qual:3.12.0'
|
||||
@@ -87,7 +96,7 @@ dependencies {
|
||||
compileOnly 'redis.clients:jedis:4.4.3'
|
||||
compileOnly 'io.nats:jnats:2.16.4'
|
||||
compileOnly 'com.rabbitmq:amqp-client:5.12.0'
|
||||
api 'org.mongodb:mongodb-driver-legacy:4.5.0'
|
||||
compileOnly 'org.mongodb:mongodb-driver-legacy:4.5.0'
|
||||
compileOnly 'org.postgresql:postgresql:42.6.0'
|
||||
compileOnly 'org.yaml:snakeyaml:1.28'
|
||||
}
|
||||
|
@@ -42,6 +42,10 @@ public class Log {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static Log of(List<LoggedAction> content) {
|
||||
return content.isEmpty() ? EMPTY : new Log(content);
|
||||
}
|
||||
|
||||
public static Log empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
@@ -37,6 +37,10 @@ public class LogPage {
|
||||
return new LogPage.Builder();
|
||||
}
|
||||
|
||||
public static LogPage of(List<LoggedAction> content) {
|
||||
return content.isEmpty() ? EMPTY : new LogPage(content);
|
||||
}
|
||||
|
||||
public static LogPage empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ public final class ActionFilterMongoBuilder extends FilterMongoBuilder<Action> {
|
||||
if (value instanceof String | value instanceof UUID) {
|
||||
return value;
|
||||
} else if (value instanceof Action.Target.Type) {
|
||||
return LoggedAction.getTypeString((Action.Target.Type) value);
|
||||
return ((Action.Target.Type) value).name();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to map value with type: " + value.getClass().getName());
|
||||
}
|
||||
|
@@ -25,6 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class PageParameters {
|
||||
|
||||
private final int pageSize;
|
||||
@@ -43,4 +47,18 @@ public class PageParameters {
|
||||
return this.pageNumber;
|
||||
}
|
||||
|
||||
public <T> List<T> paginate(List<T> input) {
|
||||
int fromIndex = this.pageSize * (this.pageNumber - 1);
|
||||
if (fromIndex >= input.size()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
int toIndex = Math.min(fromIndex + this.pageSize, input.size());
|
||||
return input.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
public <T> Stream<T> paginate(Stream<T> input) {
|
||||
return input.skip((long) this.pageSize * (this.pageNumber - 1)).limit(this.pageSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ public class ConstraintMongoBuilder {
|
||||
public static <R> FindIterable<R> page(PageParameters pageParameters, FindIterable<R> iterable) {
|
||||
int pageSize = pageParameters.pageSize();
|
||||
int pageNumber = pageParameters.pageNumber();
|
||||
return iterable.limit(pageNumber).skip((pageNumber - 1) * pageSize);
|
||||
return iterable.limit(pageSize).skip((pageNumber - 1) * pageSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,12 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.filter.mongo;
|
||||
|
||||
import com.mongodb.client.FindIterable;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import me.lucko.luckperms.common.filter.Filter;
|
||||
import me.lucko.luckperms.common.filter.FilterField;
|
||||
import me.lucko.luckperms.common.filter.FilterList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import org.bson.conversions.Bson;
|
||||
|
||||
import java.util.List;
|
||||
@@ -64,10 +62,4 @@ public abstract class FilterMongoBuilder<T> extends ConstraintMongoBuilder {
|
||||
return make(filters.operator(), filters);
|
||||
}
|
||||
|
||||
public static <R> FindIterable<R> page(PageParameters pageParameters, FindIterable<R> iterable) {
|
||||
int pageSize = pageParameters.pageSize();
|
||||
int pageNumber = pageParameters.pageNumber();
|
||||
return iterable.limit(pageNumber).skip((pageNumber - 1) * pageSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -177,7 +177,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
|
||||
|
||||
@Override
|
||||
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
return this.actionLogger.getLogPage(filters, page);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -25,12 +25,14 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.file;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import me.lucko.luckperms.common.actionlog.ActionJsonSerializer;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.cache.BufferedRequest;
|
||||
import me.lucko.luckperms.common.filter.FilterList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
@@ -45,11 +47,14 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileActionLogger {
|
||||
|
||||
@@ -133,36 +138,37 @@ public class FileActionLogger {
|
||||
}
|
||||
}
|
||||
|
||||
public Log getLog() throws IOException {
|
||||
private Stream<LoggedAction> getRawLog() throws IOException {
|
||||
// if there is log content waiting to be written, flush immediately before trying to read
|
||||
if (this.saveBuffer.isEnqueued()) {
|
||||
this.saveBuffer.requestDirectly();
|
||||
}
|
||||
|
||||
if (!Files.exists(this.contentFile)) {
|
||||
return Log.empty();
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
Log.Builder log = Log.builder();
|
||||
|
||||
Stream.Builder<LoggedAction> builder = Stream.builder();
|
||||
try (BufferedReader reader = Files.newBufferedReader(this.contentFile, StandardCharsets.UTF_8)) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
try {
|
||||
JsonElement parsed = GsonProvider.parser().parse(line);
|
||||
log.add(ActionJsonSerializer.deserialize(parsed));
|
||||
builder.add(ActionJsonSerializer.deserialize(parsed));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
return log.build();
|
||||
public Log getLog() throws IOException {
|
||||
return Log.of(getRawLog().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws IOException {
|
||||
|
||||
|
||||
return LogPage.of(page.paginate(getRawLog().filter(filters::evaluate).sorted(Comparator.reverseOrder())).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private final class SaveBuffer extends BufferedRequest<Void> {
|
||||
|
@@ -31,11 +31,13 @@ import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoCursor;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.ReplaceOptions;
|
||||
import com.mongodb.client.model.Sorts;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
@@ -70,6 +72,7 @@ import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeBuilder;
|
||||
import org.bson.Document;
|
||||
import org.bson.UuidRepresentation;
|
||||
import org.bson.conversions.Bson;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
@@ -193,7 +196,7 @@ public class MongoStorage implements StorageImplementation {
|
||||
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception {
|
||||
LogPage.Builder log = LogPage.builder();
|
||||
MongoCollection<Document> c = this.database.getCollection(this.prefix + "action");
|
||||
try (MongoCursor<Document> cursor = FilterMongoBuilder.page(page, c.find(ActionFilterMongoBuilder.INSTANCE.make(filters))).iterator()) {
|
||||
try (MongoCursor<Document> cursor = ConstraintMongoBuilder.page(page, c.find(ActionFilterMongoBuilder.INSTANCE.make(filters)).sort(Sorts.descending("timestamp"))).iterator()) {
|
||||
while (cursor.hasNext()) {
|
||||
log.add(actionFromDoc(cursor.next()));
|
||||
}
|
||||
|
@@ -268,7 +268,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
ActionFilterSqlBuilder sqlBuilder = new ActionFilterSqlBuilder();
|
||||
sqlBuilder.builder().append(ACTION_SELECT_ALL);
|
||||
sqlBuilder.visit(filter);
|
||||
sqlBuilder.builder().append(" ORDER BY id DESC");
|
||||
sqlBuilder.builder().append(" ORDER BY time DESC");
|
||||
sqlBuilder.visit(page);
|
||||
|
||||
try (PreparedStatement ps = sqlBuilder.builder().build(c, this.statementProcessor)) {
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.misc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -54,6 +56,10 @@ public class StorageCredentials {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public StorageCredentials(String address, String database, String username, String password) {
|
||||
this(address, database, username, password, 10, 10, 1800000, 0, 5000, ImmutableMap.of());
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return Objects.requireNonNull(this.address, "address");
|
||||
}
|
||||
|
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.storage;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.event.EventDispatcher;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PrimaryGroupHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
||||
import me.lucko.luckperms.common.model.manager.group.StandardGroupManager;
|
||||
import me.lucko.luckperms.common.model.manager.user.StandardUserManager;
|
||||
import me.lucko.luckperms.common.model.manager.user.UserManager;
|
||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.node.types.Permission;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.model.PlayerSaveResult;
|
||||
import net.luckperms.api.model.PlayerSaveResult.Outcome;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.InheritanceNode;
|
||||
import net.luckperms.api.node.types.PermissionNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.AdditionalAnswers.answer;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public abstract class AbstractStorageTest {
|
||||
|
||||
@Mock protected LuckPermsPlugin plugin;
|
||||
@Mock protected LuckPermsBootstrap bootstrap;
|
||||
@Mock protected LuckPermsConfiguration configuration;
|
||||
|
||||
private StorageImplementation storage;
|
||||
|
||||
@BeforeEach
|
||||
public final void setupMocksAndStorage() throws Exception {
|
||||
lenient().when(this.plugin.getBootstrap()).thenReturn(this.bootstrap);
|
||||
lenient().when(this.plugin.getConfiguration()).thenReturn(this.configuration);
|
||||
lenient().when(this.plugin.getEventDispatcher()).thenReturn(mock(EventDispatcher.class));
|
||||
lenient().when(this.bootstrap.getScheduler()).thenReturn(mock(SchedulerAdapter.class));
|
||||
lenient().when(this.configuration.get(ConfigKeys.PRIMARY_GROUP_CALCULATION)).thenReturn(PrimaryGroupHolder.AllParentsByWeight::new);
|
||||
lenient().when(this.configuration.get(ConfigKeys.PRIMARY_GROUP_CALCULATION_METHOD)).thenReturn("parents-by-weight");
|
||||
lenient().when(this.bootstrap.getResourceStream(anyString()))
|
||||
.then(answer((String path) -> AbstractStorageTest.class.getClassLoader().getResourceAsStream(path)));
|
||||
lenient().when(this.plugin.getEventDispatcher()).thenReturn(mock(EventDispatcher.class));
|
||||
|
||||
this.storage = makeStorage(this.plugin);
|
||||
this.storage.init();
|
||||
}
|
||||
|
||||
protected abstract StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception;
|
||||
|
||||
protected void cleanupResources() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public final void shutdownStorage() {
|
||||
this.storage.shutdown();
|
||||
cleanupResources();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionLog() throws Exception {
|
||||
LoggedAction action = LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.USER)
|
||||
.target(UUID.randomUUID())
|
||||
.targetName("Test Target")
|
||||
.description("hello 123 hello 123")
|
||||
.build();
|
||||
|
||||
this.storage.logAction(action);
|
||||
|
||||
Log log = this.storage.getLog();
|
||||
assertEquals(1, log.getContent().size());
|
||||
assertEquals(action, log.getContent().first());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionLogPage() throws Exception {
|
||||
UUID sourceUuid = UUID.randomUUID();
|
||||
UUID targetUuid = UUID.randomUUID();
|
||||
|
||||
Instant baseTime = Instant.now();
|
||||
|
||||
Function<Integer, LoggedAction> mockAction = i -> LoggedAction.build()
|
||||
.source(i % 2 == 0 ? sourceUuid : UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.USER)
|
||||
.target(targetUuid)
|
||||
.targetName("Test Target")
|
||||
.description("hello " + i)
|
||||
.timestamp(baseTime.plusSeconds(i))
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
this.storage.logAction(mockAction.apply(-i));
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
this.storage.logAction(mockAction.apply(i));
|
||||
}
|
||||
for (int i = 100; i < 200; i++) {
|
||||
this.storage.logAction(mockAction.apply(-i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
this.storage.logAction(LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.GROUP)
|
||||
.targetName(i % 2 == 0 ? "test_group" : "dummy")
|
||||
.description("group test " + i)
|
||||
.build());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
this.storage.logAction(LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.TRACK)
|
||||
.targetName(i % 2 == 0 ? "test_track" : "dummy")
|
||||
.description("track test " + i)
|
||||
.build());
|
||||
}
|
||||
|
||||
LogPage page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 1));
|
||||
assertEquals(ImmutableList.of(
|
||||
mockAction.apply(98),
|
||||
mockAction.apply(96),
|
||||
mockAction.apply(94),
|
||||
mockAction.apply(92),
|
||||
mockAction.apply(90)
|
||||
), page.getContent());
|
||||
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 3));
|
||||
assertEquals(ImmutableList.of(
|
||||
mockAction.apply(78),
|
||||
mockAction.apply(76),
|
||||
mockAction.apply(74),
|
||||
mockAction.apply(72),
|
||||
mockAction.apply(70)
|
||||
), page.getContent());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(500, 1));
|
||||
assertEquals(150, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.all(), new PageParameters(500, 1));
|
||||
assertEquals(320, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.user(targetUuid), new PageParameters(500, 1));
|
||||
assertEquals(300, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.group("test_group"), new PageParameters(10, 1));
|
||||
assertEquals(5, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.track("test_track"), new PageParameters(10, 1));
|
||||
assertEquals(5, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.search("hello"), new PageParameters(500, 1));
|
||||
assertEquals(300, page.getContent().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavePlayerData() throws Exception {
|
||||
UUID uniqueId = UUID.randomUUID();
|
||||
|
||||
// clean insert
|
||||
PlayerSaveResult r1 = this.storage.savePlayerData(uniqueId, "Player1");
|
||||
assertEquals(ImmutableSet.of(Outcome.CLEAN_INSERT), r1.getOutcomes());
|
||||
assertNull(r1.getOtherUniqueIds());
|
||||
assertNull(r1.getPreviousUsername());
|
||||
|
||||
// no change expected
|
||||
PlayerSaveResult r2 = this.storage.savePlayerData(uniqueId, "Player1");
|
||||
assertEquals(ImmutableSet.of(Outcome.NO_CHANGE), r2.getOutcomes());
|
||||
assertNull(r2.getOtherUniqueIds());
|
||||
assertNull(r2.getPreviousUsername());
|
||||
|
||||
// changed username
|
||||
PlayerSaveResult r3 = this.storage.savePlayerData(uniqueId, "Player2");
|
||||
assertEquals(ImmutableSet.of(Outcome.USERNAME_UPDATED), r3.getOutcomes());
|
||||
assertNull(r3.getOtherUniqueIds());
|
||||
assertTrue("Player1".equalsIgnoreCase(r3.getPreviousUsername()));
|
||||
|
||||
// changed uuid
|
||||
UUID newUniqueId = UUID.randomUUID();
|
||||
PlayerSaveResult r4 = this.storage.savePlayerData(newUniqueId, "Player2");
|
||||
assertEquals(ImmutableSet.of(Outcome.CLEAN_INSERT, Outcome.OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME), r4.getOutcomes());
|
||||
assertNotNull(r4.getOtherUniqueIds());
|
||||
assertEquals(ImmutableSet.of(uniqueId), r4.getOtherUniqueIds());
|
||||
assertNull(r2.getPreviousUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlayerUniqueIdAndName() throws Exception {
|
||||
UUID uniqueId = UUID.randomUUID();
|
||||
String username = "Player1";
|
||||
|
||||
this.storage.savePlayerData(uniqueId, username);
|
||||
|
||||
assertEquals(uniqueId, this.storage.getPlayerUniqueId("Player1"));
|
||||
assertTrue(username.equalsIgnoreCase(this.storage.getPlayerName(uniqueId)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlayerUniqueIdAndNameNull() throws Exception {
|
||||
assertNull(this.storage.getPlayerUniqueId("Player1"));
|
||||
assertNull(this.storage.getPlayerName(UUID.randomUUID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndLoadGroup() throws Exception {
|
||||
StandardGroupManager groupManager = new StandardGroupManager(this.plugin);
|
||||
|
||||
//noinspection unchecked,rawtypes
|
||||
lenient().when(this.plugin.getGroupManager()).thenReturn((GroupManager) groupManager);
|
||||
|
||||
Group group = this.storage.createAndLoadGroup("test");
|
||||
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.1")
|
||||
.withContext("server", "test")
|
||||
.build()
|
||||
);
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.2")
|
||||
.withContext("world", "test")
|
||||
.build()
|
||||
);
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.3")
|
||||
.expiry(1, TimeUnit.HOURS)
|
||||
.withContext("server", "test")
|
||||
.withContext("world", "test")
|
||||
.withContext("hello", "test")
|
||||
.build()
|
||||
);
|
||||
|
||||
Set<Node> nodes = group.normalData().asSet();
|
||||
assertEquals(3, nodes.size());
|
||||
|
||||
this.storage.saveGroup(group);
|
||||
groupManager.unload("test");
|
||||
|
||||
Group loaded = this.storage.loadGroup("test").orElse(null);
|
||||
assertNotNull(loaded);
|
||||
assertNotSame(group, loaded);
|
||||
assertEquals(nodes, loaded.normalData().asSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndDeleteUser() throws Exception {
|
||||
StandardUserManager userManager = new StandardUserManager(this.plugin);
|
||||
|
||||
//noinspection unchecked,rawtypes
|
||||
when(this.plugin.getUserManager()).thenReturn((UserManager) userManager);
|
||||
|
||||
UUID exampleUniqueId = UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5");
|
||||
String exampleUsername = "Notch";
|
||||
PermissionNode examplePermission = Permission.builder()
|
||||
.permission("test.1")
|
||||
.withContext("server", "test")
|
||||
.build();
|
||||
InheritanceNode defaultGroupNode = Inheritance.builder(GroupManager.DEFAULT_GROUP_NAME).build();
|
||||
|
||||
// create a default user, assert that is doesn't appear in unique users list
|
||||
this.storage.savePlayerData(exampleUniqueId, exampleUsername);
|
||||
assertFalse(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
|
||||
// give the user a node, assert that it does appear in unique users list
|
||||
User user = this.storage.loadUser(exampleUniqueId, exampleUsername);
|
||||
user.setNode(DataType.NORMAL, examplePermission, true);
|
||||
this.storage.saveUser(user);
|
||||
assertTrue(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
|
||||
// clear all nodes (reset to default) and assert that it does not appear in unique users list
|
||||
user.clearNodes(DataType.NORMAL, null, true);
|
||||
this.storage.saveUser(user);
|
||||
assertFalse(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode), user.normalData().asSet());
|
||||
|
||||
// give it a node again, assert that it shows as a unique user
|
||||
user.setNode(DataType.NORMAL, examplePermission, true);
|
||||
this.storage.saveUser(user);
|
||||
assertTrue(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode, examplePermission), user.normalData().asSet());
|
||||
|
||||
// reload user data from the db and assert that it is unchanged
|
||||
user = this.storage.loadUser(exampleUniqueId, exampleUsername);
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode, examplePermission), user.normalData().asSet());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
package me.lucko.luckperms.common.storage;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.CombinedConfigurateStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.SeparatedConfigurateStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.HoconLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.JsonLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.TomlLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.YamlLoader;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.mockito.Mockito.lenient;
|
||||
|
||||
public class ConfigurateStorageTest {
|
||||
|
||||
@Nested
|
||||
class SeparatedYaml extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new SeparatedConfigurateStorage(plugin, "YAML", new YamlLoader(), ".yml", "yaml-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class SeparatedJson extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new SeparatedConfigurateStorage(plugin, "JSON", new JsonLoader(), ".json", "json-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class SeparatedHocon extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new SeparatedConfigurateStorage(plugin, "HOCON", new HoconLoader(), ".conf", "hocon-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class SeparatedToml extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new SeparatedConfigurateStorage(plugin, "TOML", new TomlLoader(), ".toml", "toml-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CombinedYaml extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new CombinedConfigurateStorage(plugin, "YAML", new YamlLoader(), ".yml", "yaml-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CombinedJson extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new CombinedConfigurateStorage(plugin, "JSON", new JsonLoader(), ".json", "json-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CombinedHocon extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new CombinedConfigurateStorage(plugin, "HOCON", new HoconLoader(), ".conf", "hocon-storage");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CombinedToml extends AbstractStorageTest {
|
||||
@TempDir
|
||||
private Path directory;
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
lenient().when(this.bootstrap.getDataDirectory()).thenReturn(this.directory);
|
||||
return new CombinedConfigurateStorage(plugin, "TOML", new TomlLoader(), ".toml", "toml-storage");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package me.lucko.luckperms.common.storage;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
|
||||
import me.lucko.luckperms.common.storage.implementation.mongodb.MongoStorage;
|
||||
import me.lucko.luckperms.common.storage.misc.StorageCredentials;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
//@Tag("docker")
|
||||
public class MongoStorageTest extends AbstractStorageTest {
|
||||
|
||||
private final GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("mongo"))
|
||||
.withExposedPorts(27017);
|
||||
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
this.container.start();
|
||||
String host = this.container.getHost();
|
||||
Integer port = this.container.getFirstMappedPort();
|
||||
|
||||
StorageCredentials credentials = new StorageCredentials(
|
||||
host + ":" + port,
|
||||
"minecraft",
|
||||
"",
|
||||
""
|
||||
);
|
||||
return new MongoStorage(plugin, credentials, "", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupResources() {
|
||||
this.container.stop();
|
||||
}
|
||||
}
|
@@ -25,316 +25,22 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.event.EventDispatcher;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PrimaryGroupHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
||||
import me.lucko.luckperms.common.model.manager.group.StandardGroupManager;
|
||||
import me.lucko.luckperms.common.model.manager.user.StandardUserManager;
|
||||
import me.lucko.luckperms.common.model.manager.user.UserManager;
|
||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.node.types.Permission;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.SqlStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.ConnectionFactory;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.file.NonClosableConnection;
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.model.PlayerSaveResult;
|
||||
import net.luckperms.api.model.PlayerSaveResult.Outcome;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.InheritanceNode;
|
||||
import net.luckperms.api.node.types.PermissionNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.AdditionalAnswers.answer;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
public class SqlStorageTest extends AbstractStorageTest {
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class SqlStorageTest {
|
||||
|
||||
@Mock private LuckPermsPlugin plugin;
|
||||
@Mock private LuckPermsBootstrap bootstrap;
|
||||
@Mock private LuckPermsConfiguration configuration;
|
||||
|
||||
private SqlStorage storage;
|
||||
|
||||
@BeforeEach
|
||||
public void setupMocksAndDatabase() throws Exception {
|
||||
lenient().when(this.plugin.getBootstrap()).thenReturn(this.bootstrap);
|
||||
lenient().when(this.plugin.getConfiguration()).thenReturn(this.configuration);
|
||||
lenient().when(this.plugin.getEventDispatcher()).thenReturn(mock(EventDispatcher.class));
|
||||
lenient().when(this.bootstrap.getScheduler()).thenReturn(mock(SchedulerAdapter.class));
|
||||
lenient().when(this.configuration.get(ConfigKeys.PRIMARY_GROUP_CALCULATION)).thenReturn(PrimaryGroupHolder.AllParentsByWeight::new);
|
||||
lenient().when(this.configuration.get(ConfigKeys.PRIMARY_GROUP_CALCULATION_METHOD)).thenReturn("parents-by-weight");
|
||||
lenient().when(this.bootstrap.getResourceStream(anyString()))
|
||||
.then(answer((String path) -> SqlStorageTest.class.getClassLoader().getResourceAsStream(path)));
|
||||
lenient().when(this.plugin.getEventDispatcher()).thenReturn(mock(EventDispatcher.class));
|
||||
|
||||
this.storage = new SqlStorage(this.plugin, new TestH2ConnectionFactory(), "luckperms_");
|
||||
this.storage.init();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdownDatabase() {
|
||||
this.storage.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionLog() throws Exception {
|
||||
LoggedAction action = LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.USER)
|
||||
.target(UUID.randomUUID())
|
||||
.targetName("Test Target")
|
||||
.description("hello 123 hello 123")
|
||||
.build();
|
||||
|
||||
this.storage.logAction(action);
|
||||
|
||||
Log log = this.storage.getLog();
|
||||
assertEquals(1, log.getContent().size());
|
||||
assertEquals(action, log.getContent().first());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionLogPage() throws Exception {
|
||||
UUID sourceUuid = UUID.randomUUID();
|
||||
UUID targetUuid = UUID.randomUUID();
|
||||
|
||||
Function<Integer, LoggedAction> mockAction = i -> LoggedAction.build()
|
||||
.source(i % 2 == 0 ? sourceUuid : UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.USER)
|
||||
.target(targetUuid)
|
||||
.targetName("Test Target")
|
||||
.description("hello " + i)
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
this.storage.logAction(mockAction.apply(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
this.storage.logAction(LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.GROUP)
|
||||
.targetName(i % 2 == 0 ? "test_group" : "dummy")
|
||||
.description("group test " + i)
|
||||
.build());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
this.storage.logAction(LoggedAction.build()
|
||||
.source(UUID.randomUUID())
|
||||
.sourceName("Test Source")
|
||||
.targetType(Action.Target.Type.TRACK)
|
||||
.targetName(i % 2 == 0 ? "test_track" : "dummy")
|
||||
.description("track test " + i)
|
||||
.build());
|
||||
}
|
||||
|
||||
LogPage page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 1));
|
||||
assertEquals(ImmutableList.of(
|
||||
mockAction.apply(98),
|
||||
mockAction.apply(96),
|
||||
mockAction.apply(94),
|
||||
mockAction.apply(92),
|
||||
mockAction.apply(90)
|
||||
), page.getContent());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 3));
|
||||
assertEquals(ImmutableList.of(
|
||||
mockAction.apply(78),
|
||||
mockAction.apply(76),
|
||||
mockAction.apply(74),
|
||||
mockAction.apply(72),
|
||||
mockAction.apply(70)
|
||||
), page.getContent());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(200, 1));
|
||||
assertEquals(50, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.all(), new PageParameters(200, 1));
|
||||
assertEquals(120, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.user(targetUuid), new PageParameters(200, 1));
|
||||
assertEquals(100, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.group("test_group"), new PageParameters(10, 1));
|
||||
assertEquals(5, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.track("test_track"), new PageParameters(10, 1));
|
||||
assertEquals(5, page.getContent().size());
|
||||
|
||||
page = this.storage.getLogPage(ActionFilters.search("hello"), new PageParameters(200, 1));
|
||||
assertEquals(100, page.getContent().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavePlayerData() throws Exception {
|
||||
UUID uniqueId = UUID.randomUUID();
|
||||
|
||||
// clean insert
|
||||
PlayerSaveResult r1 = this.storage.savePlayerData(uniqueId, "Player1");
|
||||
assertEquals(ImmutableSet.of(Outcome.CLEAN_INSERT), r1.getOutcomes());
|
||||
assertNull(r1.getOtherUniqueIds());
|
||||
assertNull(r1.getPreviousUsername());
|
||||
|
||||
// no change expected
|
||||
PlayerSaveResult r2 = this.storage.savePlayerData(uniqueId, "Player1");
|
||||
assertEquals(ImmutableSet.of(Outcome.NO_CHANGE), r2.getOutcomes());
|
||||
assertNull(r2.getOtherUniqueIds());
|
||||
assertNull(r2.getPreviousUsername());
|
||||
|
||||
// changed username
|
||||
PlayerSaveResult r3 = this.storage.savePlayerData(uniqueId, "Player2");
|
||||
assertEquals(ImmutableSet.of(Outcome.USERNAME_UPDATED), r3.getOutcomes());
|
||||
assertNull(r3.getOtherUniqueIds());
|
||||
assertTrue("Player1".equalsIgnoreCase(r3.getPreviousUsername()));
|
||||
|
||||
// changed uuid
|
||||
UUID newUniqueId = UUID.randomUUID();
|
||||
PlayerSaveResult r4 = this.storage.savePlayerData(newUniqueId, "Player2");
|
||||
assertEquals(ImmutableSet.of(Outcome.CLEAN_INSERT, Outcome.OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME), r4.getOutcomes());
|
||||
assertNotNull(r4.getOtherUniqueIds());
|
||||
assertEquals(ImmutableSet.of(uniqueId), r4.getOtherUniqueIds());
|
||||
assertNull(r2.getPreviousUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlayerUniqueIdAndName() throws Exception {
|
||||
UUID uniqueId = UUID.randomUUID();
|
||||
String username = "Player1";
|
||||
|
||||
this.storage.savePlayerData(uniqueId, username);
|
||||
|
||||
assertEquals(uniqueId, this.storage.getPlayerUniqueId("Player1"));
|
||||
assertTrue(username.equalsIgnoreCase(this.storage.getPlayerName(uniqueId)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlayerUniqueIdAndNameNull() throws Exception {
|
||||
assertNull(this.storage.getPlayerUniqueId("Player1"));
|
||||
assertNull(this.storage.getPlayerName(UUID.randomUUID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndLoadGroup() throws Exception {
|
||||
StandardGroupManager groupManager = new StandardGroupManager(this.plugin);
|
||||
|
||||
//noinspection unchecked,rawtypes
|
||||
lenient().when(this.plugin.getGroupManager()).thenReturn((GroupManager) groupManager);
|
||||
|
||||
Group group = this.storage.createAndLoadGroup("test");
|
||||
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.1")
|
||||
.withContext("server", "test")
|
||||
.build()
|
||||
);
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.2")
|
||||
.withContext("world", "test")
|
||||
.build()
|
||||
);
|
||||
group.normalData().add(Permission.builder()
|
||||
.permission("test.3")
|
||||
.expiry(1, TimeUnit.HOURS)
|
||||
.withContext("server", "test")
|
||||
.withContext("world", "test")
|
||||
.withContext("hello", "test")
|
||||
.build()
|
||||
);
|
||||
|
||||
Set<Node> nodes = group.normalData().asSet();
|
||||
assertEquals(3, nodes.size());
|
||||
|
||||
this.storage.saveGroup(group);
|
||||
groupManager.unload("test");
|
||||
|
||||
Group loaded = this.storage.loadGroup("test").orElse(null);
|
||||
assertNotNull(loaded);
|
||||
assertNotSame(group, loaded);
|
||||
assertEquals(nodes, loaded.normalData().asSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndDeleteUser() throws SQLException {
|
||||
StandardUserManager userManager = new StandardUserManager(this.plugin);
|
||||
|
||||
//noinspection unchecked,rawtypes
|
||||
when(this.plugin.getUserManager()).thenReturn((UserManager) userManager);
|
||||
|
||||
UUID exampleUniqueId = UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5");
|
||||
String exampleUsername = "Notch";
|
||||
PermissionNode examplePermission = Permission.builder()
|
||||
.permission("test.1")
|
||||
.withContext("server", "test")
|
||||
.build();
|
||||
InheritanceNode defaultGroupNode = Inheritance.builder(GroupManager.DEFAULT_GROUP_NAME).build();
|
||||
|
||||
// create a default user, assert that is doesn't appear in unique users list
|
||||
this.storage.savePlayerData(exampleUniqueId, exampleUsername);
|
||||
assertFalse(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
|
||||
// give the user a node, assert that it does appear in unique users list
|
||||
User user = this.storage.loadUser(exampleUniqueId, exampleUsername);
|
||||
user.setNode(DataType.NORMAL, examplePermission, true);
|
||||
this.storage.saveUser(user);
|
||||
assertTrue(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
|
||||
// clear all nodes (reset to default) and assert that it does not appear in unique users list
|
||||
user.clearNodes(DataType.NORMAL, null, true);
|
||||
this.storage.saveUser(user);
|
||||
assertFalse(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode), user.normalData().asSet());
|
||||
|
||||
// give it a node again, assert that it shows as a unique user
|
||||
user.setNode(DataType.NORMAL, examplePermission, true);
|
||||
this.storage.saveUser(user);
|
||||
assertTrue(this.storage.getUniqueUsers().contains(exampleUniqueId));
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode, examplePermission), user.normalData().asSet());
|
||||
|
||||
// reload user data from the db and assert that it is unchanged
|
||||
user = this.storage.loadUser(exampleUniqueId, exampleUsername);
|
||||
assertEquals(ImmutableSet.of(defaultGroupNode, examplePermission), user.normalData().asSet());
|
||||
@Override
|
||||
protected StorageImplementation makeStorage(LuckPermsPlugin plugin) throws Exception {
|
||||
return new SqlStorage(plugin, new TestH2ConnectionFactory(), "luckperms_");
|
||||
}
|
||||
|
||||
private static class TestH2ConnectionFactory implements ConnectionFactory {
|
||||
@@ -379,5 +85,4 @@ public class SqlStorageTest {
|
||||
this.connection.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user