Fixed inconsistency issues related to activity index SQL

- Subquery was not returning rows for active playtime of 0, fix: COALESCE
- Union was removing duplicate 0s, replaced with UNION ALL
- Query did not use floating point for calculation

Affects issues:
- Fixed #1388
This commit is contained in:
Risto Lahtela 2020-05-08 20:53:52 +03:00
parent 6ee06d1cf8
commit b375661047
8 changed files with 239 additions and 101 deletions

View File

@ -17,15 +17,13 @@
package com.djrapitops.plan.delivery.domain.mutators;
import com.djrapitops.plan.delivery.domain.container.DataContainer;
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
import com.djrapitops.plan.delivery.formatting.Formatter;
import com.djrapitops.plan.gathering.domain.Session;
import com.djrapitops.plan.settings.locale.Locale;
import com.djrapitops.plan.settings.locale.lang.HtmlLang;
import com.djrapitops.plugin.api.TimeAmount;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* Represents Activity index of a player at a certain date.
@ -112,10 +110,7 @@ public class ActivityIndex {
}
private double calculate(DataContainer container) {
Optional<List<Session>> sessionsValue = container.getValue(PlayerKeys.SESSIONS);
return sessionsValue
.map(sessions -> calculate(new SessionsMutator(sessions)))
.orElse(0.0);
return calculate(SessionsMutator.forContainer(container));
}
private double calculate(SessionsMutator sessionsMutator) {
@ -123,7 +118,7 @@ public class ActivityIndex {
return 0.0;
}
long week = TimeAmount.WEEK.toMillis(1L);
long week = TimeUnit.DAYS.toMillis(7L);
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
@ -132,13 +127,13 @@ public class ActivityIndex {
SessionsMutator weekTwo = sessionsMutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
SessionsMutator weekThree = sessionsMutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
long playtime1 = weekOne.toActivePlaytime();
long playtime2 = weekTwo.toActivePlaytime();
long playtime3 = weekThree.toActivePlaytime();
double playtime1 = weekOne.toActivePlaytime();
double playtime2 = weekTwo.toActivePlaytime();
double playtime3 = weekThree.toActivePlaytime();
double indexW1 = 1.0 / (Math.PI / 2.0 * (playtime1 * 1.0 / playtimeMsThreshold) + 1.0);
double indexW2 = 1.0 / (Math.PI / 2.0 * (playtime2 * 1.0 / playtimeMsThreshold) + 1.0);
double indexW3 = 1.0 / (Math.PI / 2.0 * (playtime3 * 1.0 / playtimeMsThreshold) + 1.0);
double indexW1 = 1.0 / (Math.PI / 2.0 * (playtime1 / playtimeMsThreshold) + 1.0);
double indexW2 = 1.0 / (Math.PI / 2.0 * (playtime2 / playtimeMsThreshold) + 1.0);
double indexW3 = 1.0 / (Math.PI / 2.0 * (playtime3 / playtimeMsThreshold) + 1.0);
double average = (indexW1 + indexW2 + indexW3) / 3.0;

View File

@ -197,7 +197,7 @@ public class SessionsMutator {
return session -> {
Long start = session.getUnsafe(SessionKeys.START);
long end = session.getValue(SessionKeys.END).orElse(System.currentTimeMillis());
return (after <= start && start <= before) || (after <= end && end <= before);
return (after <= end && start <= before);
};
}

View File

@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit;
*/
public class Session extends DynamicDataContainer implements DateHolder {
private long sessionStart;
private final long sessionStart;
private WorldTimes worldTimes;
private List<PlayerKill> playerKills;
@ -74,7 +74,7 @@ public class Session extends DynamicDataContainer implements DateHolder {
putSupplier(SessionKeys.PLAYER_KILL_COUNT, getUnsafe(SessionKeys.PLAYER_KILLS)::size);
putSupplier(SessionKeys.LENGTH, () ->
getValue(SessionKeys.END).orElse(System.currentTimeMillis()) - getUnsafe(SessionKeys.START));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getUnsafe(SessionKeys.LENGTH) - getUnsafe(SessionKeys.AFK_TIME));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getLength() - this.afkTime);
}
/**
@ -119,7 +119,7 @@ public class Session extends DynamicDataContainer implements DateHolder {
putSupplier(SessionKeys.PLAYER_KILL_COUNT, () -> getUnsafe(SessionKeys.PLAYER_KILLS).size());
putSupplier(SessionKeys.LENGTH, () ->
getValue(SessionKeys.END).orElse(System.currentTimeMillis()) - getUnsafe(SessionKeys.START));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getUnsafe(SessionKeys.LENGTH) - getUnsafe(SessionKeys.AFK_TIME));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getLength() - this.afkTime);
}
/**

View File

@ -74,20 +74,21 @@ public class ActivityIndexQueries {
public static String selectActivityIndexSQL() {
String selectActivePlaytimeSQL = SELECT +
SessionsTable.USER_UUID +
",SUM(" +
SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME +
") as active_playtime" +
"ux." + UserInfoTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
FROM + UserInfoTable.TABLE_NAME + " ux" +
LEFT_JOIN + '(' + SELECT + SessionsTable.USER_UUID +
",SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME + ") as active_playtime" +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SERVER_UUID + "=?" +
AND + SessionsTable.SESSION_START + ">=?" +
AND + SessionsTable.SESSION_END + "<=?" +
GROUP_BY + SessionsTable.USER_UUID;
AND + SessionsTable.SESSION_END + ">=?" +
AND + SessionsTable.SESSION_START + "<=?" +
GROUP_BY + SessionsTable.USER_UUID +
") sx on sx.uuid=ux.uuid";
String selectThreeWeeks = selectActivePlaytimeSQL + UNION + selectActivePlaytimeSQL + UNION + selectActivePlaytimeSQL;
String selectThreeWeeks = selectActivePlaytimeSQL + UNION_ALL + selectActivePlaytimeSQL + UNION_ALL + selectActivePlaytimeSQL;
return SELECT +
"5.0 - 5.0 * AVG(1 / (?/2 * (q1.active_playtime/?) +1)) as activity_index," +
"5.0 - 5.0 * AVG(1.0 / (?/2.0 * (q1.active_playtime/?) +1.0)) as activity_index," +
"q1." + SessionsTable.USER_UUID +
FROM + '(' + selectThreeWeeks + ") q1" +
GROUP_BY + "q1." + SessionsTable.USER_UUID;

View File

@ -77,19 +77,20 @@ public class NetworkActivityIndexQueries {
public static String selectActivityIndexSQL() {
String selectActivePlaytimeSQL = SELECT +
SessionsTable.USER_UUID +
",SUM(" +
SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME +
") as active_playtime" +
"ux." + UsersTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
FROM + UsersTable.TABLE_NAME + " ux" +
LEFT_JOIN + '(' + SELECT + SessionsTable.USER_UUID +
",SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME + ") as active_playtime" +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SESSION_START + ">=?" +
AND + SessionsTable.SESSION_END + "<=?" +
GROUP_BY + SessionsTable.USER_UUID;
WHERE + SessionsTable.SESSION_END + ">=?" +
AND + SessionsTable.SESSION_START + "<=?" +
GROUP_BY + SessionsTable.USER_UUID +
") sx on sx.uuid=ux.uuid";
String selectThreeWeeks = selectActivePlaytimeSQL + UNION + selectActivePlaytimeSQL + UNION + selectActivePlaytimeSQL;
String selectThreeWeeks = selectActivePlaytimeSQL + UNION_ALL + selectActivePlaytimeSQL + UNION_ALL + selectActivePlaytimeSQL;
return SELECT +
"5.0 - 5.0 * AVG(1 / (?/2 * (q1.active_playtime/?) +1)) as activity_index," +
"5.0 - 5.0 * AVG(1.0 / (?/2.0 * (q1.active_playtime/?) +1.0)) as activity_index," +
"q1." + SessionsTable.USER_UUID +
FROM + '(' + selectThreeWeeks + ") q1" +
GROUP_BY + "q1." + SessionsTable.USER_UUID;

View File

@ -43,6 +43,7 @@ public abstract class Sql {
public static final String INNER_JOIN = " JOIN ";
public static final String LEFT_JOIN = " LEFT JOIN ";
public static final String UNION = " UNION ";
public static final String UNION_ALL = " UNION ALL ";
public static final String AND = " AND ";
public static final String OR = " OR ";
public static final String IS_NULL = " IS NULL";

View File

@ -17,30 +17,40 @@
package com.djrapitops.plan.storage.database.queries;
import com.djrapitops.plan.delivery.domain.TablePlayer;
import com.djrapitops.plan.delivery.domain.keys.SessionKeys;
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
import com.djrapitops.plan.gathering.domain.Session;
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQueries;
import com.djrapitops.plan.storage.database.queries.objects.NetworkTablePlayersQuery;
import com.djrapitops.plan.storage.database.queries.objects.ServerTablePlayersQuery;
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
import com.djrapitops.plan.storage.database.transactions.events.PlayerServerRegisterTransaction;
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import utilities.RandomData;
import utilities.TestConstants;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
import static org.junit.jupiter.api.Assertions.*;
public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
default void storeSessions() {
default void storeSessions(Predicate<Session> save) {
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, RandomData::randomTime, TestConstants.PLAYER_ONE_NAME, serverUUID()));
db().executeTransaction(new PlayerServerRegisterTransaction(player2UUID, RandomData::randomTime, TestConstants.PLAYER_TWO_NAME, serverUUID()));
for (String world : worlds) {
@ -48,7 +58,7 @@ public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
}
for (Session session : RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID)) {
execute(DataStoreQueries.storeSession(session));
if (save.test(session)) execute(DataStoreQueries.storeSession(session));
}
}
@ -62,9 +72,9 @@ public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
// assertEquals(expected, groupings);
// }
@Test
@RepeatedTest(3)
default void activityIndexCalculationsMatch() {
storeSessions();
storeSessions(session -> true);
long date = System.currentTimeMillis();
long playtimeThreshold = TimeUnit.HOURS.toMillis(5L);
@ -79,12 +89,85 @@ public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
Optional<ActivityIndex> currentActivityIndex = found.get().getCurrentActivityIndex();
assertTrue(currentActivityIndex.isPresent());
assertEquals(javaCalculation.getValue(), currentActivityIndex.get().getValue(), 0.001);
assertEquals(javaCalculation.getValue(), currentActivityIndex.get().getValue(), 0.001, () -> {
StringBuilder errorMsg = new StringBuilder("Activity indexes did not match\n");
long week = TimeUnit.DAYS.toMillis(7L);
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
SessionsMutator mutator = new SessionsMutator(sessions);
SessionsMutator w1 = mutator.filterSessionsBetween(weekAgo, date);
SessionsMutator w2 = mutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
SessionsMutator w3 = mutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
Long dbW1 = db().query(SessionQueries.activePlaytime(weekAgo, date, serverUUID()));
Long dbW2 = db().query(SessionQueries.activePlaytime(twoWeeksAgo, weekAgo, serverUUID()));
Long dbW3 = db().query(SessionQueries.activePlaytime(threeWeeksAgo, twoWeeksAgo, serverUUID()));
errorMsg.append("Java calculation playtimes: ")
.append(w1.toActivePlaytime()).append("ms,")
.append(w2.toActivePlaytime()).append("ms,")
.append(w3.toActivePlaytime()).append("ms\n")
.append("DB calculation playtimes: ")
.append(dbW1).append("ms,")
.append(dbW2).append("ms,")
.append(dbW3).append("ms");
return errorMsg.toString();
});
}
@Test
@RepeatedTest(3)
default void activityIndexCalculationsMatchWithMissingData() {
long keepAfter = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7L);
storeSessions(session -> session.getDate() >= keepAfter && session.getUnsafe(SessionKeys.END) >= keepAfter);
long date = System.currentTimeMillis();
long playtimeThreshold = TimeUnit.HOURS.toMillis(5L);
List<Session> sessions = db().query(SessionQueries.fetchSessionsOfPlayer(playerUUID))
.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
ActivityIndex javaCalculation = new ActivityIndex(sessions, date, playtimeThreshold);
List<TablePlayer> players = db().query(new ServerTablePlayersQuery(serverUUID(), date, playtimeThreshold, 5));
Optional<TablePlayer> found = players.stream().filter(tp -> playerUUID.equals(tp.getPlayerUUID())).findFirst();
assertTrue(found.isPresent());
Optional<ActivityIndex> currentActivityIndex = found.get().getCurrentActivityIndex();
assertTrue(currentActivityIndex.isPresent());
assertEquals(javaCalculation.getValue(), currentActivityIndex.get().getValue(), 0.001, () -> {
StringBuilder errorMsg = new StringBuilder("Activity indexes did not match\n");
long week = TimeUnit.DAYS.toMillis(7L);
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
SessionsMutator mutator = new SessionsMutator(sessions);
SessionsMutator w1 = mutator.filterSessionsBetween(weekAgo, date);
SessionsMutator w2 = mutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
SessionsMutator w3 = mutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
Long dbW1 = db().query(SessionQueries.activePlaytime(weekAgo, date, serverUUID()));
Long dbW2 = db().query(SessionQueries.activePlaytime(twoWeeksAgo, weekAgo, serverUUID()));
Long dbW3 = db().query(SessionQueries.activePlaytime(threeWeeksAgo, twoWeeksAgo, serverUUID()));
errorMsg.append("Java calculation playtimes: ")
.append(w1.toActivePlaytime()).append("ms,")
.append(w2.toActivePlaytime()).append("ms,")
.append(w3.toActivePlaytime()).append("ms\n")
.append("DB calculation playtimes: ")
.append(dbW1).append("ms,")
.append(dbW2).append("ms,")
.append(dbW3).append("ms");
return errorMsg.toString();
});
}
@RepeatedTest(3)
default void networkActivityIndexCalculationsMatch() {
storeSessions();
storeSessions(session -> true);
long date = System.currentTimeMillis();
long playtimeThreshold = TimeUnit.HOURS.toMillis(5L);
@ -99,7 +182,58 @@ public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
Optional<ActivityIndex> currentActivityIndex = found.get().getCurrentActivityIndex();
assertTrue(currentActivityIndex.isPresent());
assertEquals(javaCalculation.getValue(), currentActivityIndex.get().getValue(), 0.001);
assertEquals(javaCalculation.getValue(), currentActivityIndex.get().getValue(), 0.001, () -> {
StringBuilder errorMsg = new StringBuilder("Activity indexes did not match\n");
long week = TimeUnit.DAYS.toMillis(7L);
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
SessionsMutator mutator = new SessionsMutator(sessions);
SessionsMutator w1 = mutator.filterSessionsBetween(weekAgo, date);
SessionsMutator w2 = mutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
SessionsMutator w3 = mutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
Long dbW1 = db().query(activePlaytime(weekAgo, date));
Long dbW2 = db().query(activePlaytime(twoWeeksAgo, weekAgo));
Long dbW3 = db().query(activePlaytime(threeWeeksAgo, twoWeeksAgo));
errorMsg.append("Java calculation playtimes: ")
.append(w1.toActivePlaytime()).append("ms,")
.append(w2.toActivePlaytime()).append("ms,")
.append(w3.toActivePlaytime()).append("ms\n")
.append("DB calculation playtimes: ")
.append(dbW1).append("ms,")
.append(dbW2).append("ms,")
.append(dbW3).append("ms");
return errorMsg.toString();
});
}
default Query<Long> activePlaytime(long after, long before) {
String sql = SELECT +
"ux." + UsersTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
FROM + UsersTable.TABLE_NAME + " ux" +
LEFT_JOIN + '(' + SELECT + SessionsTable.USER_UUID +
",SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME + ") as active_playtime" +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SESSION_END + ">=?" +
AND + SessionsTable.SESSION_START + "<=?" +
GROUP_BY + SessionsTable.USER_UUID +
") sx on sx.uuid=ux.uuid";
return new QueryStatement<Long>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setLong(1, after);
statement.setLong(2, before);
}
@Override
public Long processResults(ResultSet set) throws SQLException {
return set.next() ? set.getLong("active_playtime") : 0L;
}
};
}
@Test

View File

@ -16,24 +16,31 @@
*/
package com.djrapitops.plan.storage.database.queries;
import com.djrapitops.plan.delivery.domain.TablePlayer;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.domain.keys.SessionKeys;
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
import com.djrapitops.plan.gathering.domain.PlayerKill;
import com.djrapitops.plan.gathering.domain.Session;
import com.djrapitops.plan.gathering.domain.WorldTimes;
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
import com.djrapitops.plan.storage.database.queries.containers.PlayerContainerQuery;
import com.djrapitops.plan.storage.database.queries.objects.KillQueries;
import com.djrapitops.plan.storage.database.queries.objects.ServerTablePlayersQuery;
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
import com.djrapitops.plan.storage.database.queries.objects.WorldTimesQueries;
import com.djrapitops.plan.storage.database.transactions.Transaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
import com.djrapitops.plan.storage.database.transactions.events.PlayerServerRegisterTransaction;
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
import com.djrapitops.plugin.api.TimeAmount;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import utilities.RandomData;
import utilities.TestConstants;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
@ -258,61 +265,60 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
assertEquals(new HashSet<>(Arrays.asList(expected)), result);
}
// Tests to reproduce an issue, flaky.
// @Test
// default void playersTableAndPlayerPagePlaytimeMatches() {
// prepareForSessionSave();
// List<Session> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
// List<Session> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
// player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
// player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
//
// long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
//
// PlayerContainer playerContainer = db().query(new PlayerContainerQuery(playerUUID));
// TablePlayer tablePlayer = db().query(new ServerTablePlayersQuery(serverUUID(), System.currentTimeMillis(), playtimeThreshold, 5))
// .stream().filter(player -> playerUUID.equals(player.getPlayerUUID())).findAny()
// .orElseThrow(AssertionError::new);
//
// long expected = SessionsMutator.forContainer(playerContainer).toPlaytime();
// long got = tablePlayer.getPlaytime().orElseThrow(AssertionError::new);
// assertEquals(expected, got);
// }
//
// @Test
// default void playersTableAndPlayerPageActivityIndexMatches() {
// prepareForSessionSave();
// List<Session> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
// List<Session> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
// player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
// player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
//
// long time = System.currentTimeMillis();
// long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
//
// PlayerContainer playerContainer = db().query(new PlayerContainerQuery(playerUUID));
// TablePlayer tablePlayer = db().query(new ServerTablePlayersQuery(serverUUID(), time, playtimeThreshold, 5))
// .stream().filter(player -> playerUUID.equals(player.getPlayerUUID())).findAny()
// .orElseThrow(AssertionError::new);
//
// SessionsMutator sessionsMutator = SessionsMutator.forContainer(playerContainer);
// long week = TimeAmount.WEEK.toMillis(1L);
// long weekAgo = time - week;
// long twoWeeksAgo = time - 2L * week;
// long threeWeeksAgo = time - 3L * week;
// SessionsMutator weekOne = sessionsMutator.filterSessionsBetween(weekAgo, time);
// SessionsMutator weekTwo = sessionsMutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
// SessionsMutator weekThree = sessionsMutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
//
// long playtime1 = weekOne.toActivePlaytime();
// long playtime2 = weekTwo.toActivePlaytime();
// long playtime3 = weekThree.toActivePlaytime();
//
// double expected = playerContainer.getActivityIndex(time, playtimeThreshold).getValue();
// double got = tablePlayer.getCurrentActivityIndex().orElseThrow(AssertionError::new).getValue();
// assertEquals(expected, got, 0.00001,
// () -> "Activity Indexes between queries differed, expected: <" + expected + "> but was: <" + got + ">" +
// ". Playtime for reference container: <w1:" + playtime1 + ", w2:" + playtime2 + ", w3:" + playtime3 + ">"
// );
// }
@RepeatedTest(3)
default void playersTableAndPlayerPagePlaytimeMatches() {
prepareForSessionSave();
List<Session> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
List<Session> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
PlayerContainer playerContainer = db().query(new PlayerContainerQuery(playerUUID));
TablePlayer tablePlayer = db().query(new ServerTablePlayersQuery(serverUUID(), System.currentTimeMillis(), playtimeThreshold, 5))
.stream().filter(player -> playerUUID.equals(player.getPlayerUUID())).findAny()
.orElseThrow(AssertionError::new);
long expected = SessionsMutator.forContainer(playerContainer).toPlaytime();
long got = tablePlayer.getPlaytime().orElseThrow(AssertionError::new);
assertEquals(expected, got);
}
@RepeatedTest(3)
default void playersTableAndPlayerPageActivityIndexMatches() {
prepareForSessionSave();
List<Session> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
List<Session> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
long time = System.currentTimeMillis();
long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
PlayerContainer playerContainer = db().query(new PlayerContainerQuery(playerUUID));
TablePlayer tablePlayer = db().query(new ServerTablePlayersQuery(serverUUID(), time, playtimeThreshold, 5))
.stream().filter(player -> playerUUID.equals(player.getPlayerUUID())).findAny()
.orElseThrow(AssertionError::new);
SessionsMutator sessionsMutator = SessionsMutator.forContainer(playerContainer);
long week = TimeAmount.WEEK.toMillis(1L);
long weekAgo = time - week;
long twoWeeksAgo = time - 2L * week;
long threeWeeksAgo = time - 3L * week;
SessionsMutator weekOne = sessionsMutator.filterSessionsBetween(weekAgo, time);
SessionsMutator weekTwo = sessionsMutator.filterSessionsBetween(twoWeeksAgo, weekAgo);
SessionsMutator weekThree = sessionsMutator.filterSessionsBetween(threeWeeksAgo, twoWeeksAgo);
long playtime1 = weekOne.toActivePlaytime();
long playtime2 = weekTwo.toActivePlaytime();
long playtime3 = weekThree.toActivePlaytime();
double expected = playerContainer.getActivityIndex(time, playtimeThreshold).getValue();
double got = tablePlayer.getCurrentActivityIndex().orElseThrow(AssertionError::new).getValue();
assertEquals(expected, got, 0.001,
() -> "Activity Indexes between queries differed, expected: <" + expected + "> but was: <" + got + ">" +
". Playtime for reference container: <w1:" + playtime1 + ", w2:" + playtime2 + ", w3:" + playtime3 + ">"
);
}
}