mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-02-03 14:01:47 +01:00
parent
155910554f
commit
a773c4c46e
@ -34,13 +34,14 @@ import com.djrapitops.plan.storage.database.transactions.events.StoreWorldNameTr
|
||||
import extension.SeleniumExtension;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.logging.LogEntry;
|
||||
import org.openqa.selenium.logging.LogType;
|
||||
import org.testcontainers.containers.BindMode;
|
||||
import org.testcontainers.containers.NginxContainer;
|
||||
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import utilities.RandomData;
|
||||
import utilities.TestConstants;
|
||||
@ -68,32 +69,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ExtendWith(SeleniumExtension.class)
|
||||
class ExportJSErrorRegressionTest {
|
||||
|
||||
static Path tempDir;
|
||||
static NginxContainer<?> nginx = new NginxContainer<>("nginx:latest")
|
||||
.waitingFor(new HttpWaitStrategy());
|
||||
|
||||
static Path exportDirectory;
|
||||
|
||||
static {
|
||||
try {
|
||||
tempDir = Files.createTempDirectory("export-test");
|
||||
exportDirectory = tempDir.resolve("export");
|
||||
|
||||
Files.createDirectories(exportDirectory);
|
||||
Files.write(exportDirectory.resolve("index.html"), new byte[1]);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PluginMockComponent component;
|
||||
|
||||
@Container
|
||||
public static NginxContainer<?> nginx = new NginxContainer<>("nginx:latest")
|
||||
.withCustomContent(exportDirectory.toFile().getAbsolutePath())
|
||||
.waitingFor(new HttpWaitStrategy());
|
||||
private static PlanSystem planSystem;
|
||||
private static ServerUUID serverUUID;
|
||||
static PluginMockComponent component;
|
||||
static PlanSystem planSystem;
|
||||
static ServerUUID serverUUID;
|
||||
|
||||
@BeforeAll
|
||||
static void setUpClass() throws Exception {
|
||||
static void setUpClass(@TempDir Path tempDir) throws Exception {
|
||||
exportDirectory = tempDir.resolve("export");
|
||||
Files.createDirectories(exportDirectory);
|
||||
Files.write(exportDirectory.resolve("index.html"), new byte[1]);
|
||||
|
||||
nginx.addFileSystemBind(exportDirectory.toFile().getAbsolutePath(), "/usr/share/nginx/html", BindMode.READ_ONLY);
|
||||
nginx.start();
|
||||
|
||||
component = new PluginMockComponent(tempDir);
|
||||
planSystem = component.getPlanSystem();
|
||||
|
||||
@ -106,7 +99,7 @@ class ExportJSErrorRegressionTest {
|
||||
config.set(ExportSettings.SERVER_PAGE, true);
|
||||
config.set(ExportSettings.PLAYERS_PAGE, true);
|
||||
|
||||
config.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "");
|
||||
config.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "data:image/png;base64,AA==");
|
||||
|
||||
planSystem.enable();
|
||||
serverUUID = planSystem.getServerInfo().getServerUUID();
|
||||
@ -118,14 +111,6 @@ class ExportJSErrorRegressionTest {
|
||||
exporter.exportServerPage(planSystem.getServerInfo().getServer());
|
||||
exporter.exportPlayerPage(TestConstants.PLAYER_ONE_UUID, TestConstants.PLAYER_ONE_NAME);
|
||||
exporter.exportPlayersPage();
|
||||
|
||||
System.out.println("Exported files: \n");
|
||||
try (Stream<Path> walk = Files.walk(exportDirectory)) {
|
||||
walk.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.map(File::getAbsolutePath)
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
|
||||
private static void savePlayerData() {
|
||||
@ -139,7 +124,7 @@ class ExportJSErrorRegressionTest {
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDownClass() throws IOException {
|
||||
static void tearDownClass(@TempDir Path tempDir) throws IOException {
|
||||
if (planSystem != null) {
|
||||
planSystem.disable();
|
||||
}
|
||||
@ -171,8 +156,7 @@ class ExportJSErrorRegressionTest {
|
||||
endpoint -> DynamicTest.dynamicTest("Exported page does not log errors to js console " + endpoint, () -> {
|
||||
// Avoid accidentally DDoS:ing head image service during tests.
|
||||
planSystem.getConfigSystem().getConfig()
|
||||
.set(DisplaySettings.PLAYER_HEAD_IMG_URL, nginx.getBaseUrl("http", 80).toURI()
|
||||
.resolve("/img/Flaticon_circle.png").toString());
|
||||
.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "data:image/png;base64,AA==");
|
||||
export();
|
||||
|
||||
String address = nginx.getBaseUrl("http", 80).toURI().resolve(endpoint).toString();
|
||||
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.export;
|
||||
|
||||
import com.djrapitops.plan.PlanSystem;
|
||||
import com.djrapitops.plan.gathering.domain.DataMap;
|
||||
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DisplaySettings;
|
||||
import com.djrapitops.plan.settings.config.paths.ExportSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.PluginSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
|
||||
import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreSessionTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreWorldNameTransaction;
|
||||
import com.djrapitops.plan.storage.file.PlanFiles;
|
||||
import com.djrapitops.plan.utilities.java.Lists;
|
||||
import extension.FullSystemExtension;
|
||||
import extension.SeleniumExtension;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.*;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.logging.LogEntry;
|
||||
import org.openqa.selenium.logging.LogType;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
import utilities.RandomData;
|
||||
import utilities.TestConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@ExtendWith(SeleniumExtension.class)
|
||||
@ExtendWith(FullSystemExtension.class)
|
||||
class ExportRegressionTest {
|
||||
|
||||
public static GenericContainer<?> webserver;
|
||||
private static Path exportDir;
|
||||
private static ServerUUID serverUUID;
|
||||
|
||||
@BeforeAll
|
||||
static void setUp(PlanFiles files, PlanConfig config, PlanSystem system) throws Exception {
|
||||
exportDir = files.getDataDirectory().resolve("export");
|
||||
Files.createDirectories(exportDir);
|
||||
System.out.println("Export to " + exportDir.toFile().getAbsolutePath());
|
||||
|
||||
webserver = new GenericContainer<>(DockerImageName.parse("halverneus/static-file-server:latest"))
|
||||
.withExposedPorts(8080)
|
||||
.withFileSystemBind(exportDir.toFile().getAbsolutePath(), "/web")
|
||||
.waitingFor(new HttpWaitStrategy());
|
||||
webserver.start();
|
||||
|
||||
config.set(PluginSettings.FRONTEND_BETA, true);
|
||||
config.set(WebserverSettings.DISABLED, true);
|
||||
config.set(WebserverSettings.EXTERNAL_LINK, "http://" + webserver.getHost() + ":" + webserver.getMappedPort(8080));
|
||||
// Avoid accidentally DDoS:ing head image service during tests.
|
||||
config.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "data:image/png;base64,AA==");
|
||||
config.set(ExportSettings.HTML_EXPORT_PATH, exportDir.toFile().getAbsolutePath());
|
||||
config.set(ExportSettings.SERVER_PAGE, true);
|
||||
config.set(ExportSettings.PLAYERS_PAGE, true);
|
||||
config.set(ExportSettings.PLAYER_PAGES, true);
|
||||
|
||||
system.enable();
|
||||
serverUUID = system.getServerInfo().getServerUUID();
|
||||
savePlayerData(system.getDatabaseSystem().getDatabase(), serverUUID);
|
||||
export(system.getExportSystem().getExporter(), system.getDatabaseSystem().getDatabase());
|
||||
}
|
||||
|
||||
private static void export(Exporter exporter, Database database) throws Exception {
|
||||
exporter.exportReact();
|
||||
assertTrue(exporter.exportServerPage(database.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID.toString()))
|
||||
.orElseThrow(AssertionError::new)));
|
||||
assertTrue(exporter.exportPlayersPage());
|
||||
assertTrue(exporter.exportPlayerPage(TestConstants.PLAYER_ONE_UUID, TestConstants.PLAYER_ONE_NAME));
|
||||
}
|
||||
|
||||
private static void savePlayerData(Database database, ServerUUID serverUUID) {
|
||||
UUID uuid = TestConstants.PLAYER_ONE_UUID;
|
||||
database.executeTransaction(new PlayerRegisterTransaction(uuid, RandomData::randomTime, TestConstants.PLAYER_ONE_NAME));
|
||||
FinishedSession session = new FinishedSession(uuid, serverUUID, 1000L, 11000L, 500L, new DataMap());
|
||||
database.executeTransaction(new StoreWorldNameTransaction(serverUUID, "world"));
|
||||
database.executeTransaction(new StoreSessionTransaction(session));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown(PlanSystem system) throws IOException {
|
||||
system.disable();
|
||||
FileUtils.cleanDirectory(exportDir.toFile());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clearExportDirectory(WebDriver driver) {
|
||||
SeleniumExtension.newTab(driver);
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
Collection<DynamicTest> exportedWebpageDoesNotHaveErrors(ChromeDriver driver) throws Exception {
|
||||
List<String> endpointsToTest = Lists.builder(String.class)
|
||||
.add("/")
|
||||
.addAll(ServerPageExporter.getRedirections(serverUUID))
|
||||
.addAll(PlayerPageExporter.getRedirections(TestConstants.PLAYER_ONE_UUID))
|
||||
.add("/players")
|
||||
.build();
|
||||
|
||||
return endpointsToTest.stream().map(
|
||||
endpoint -> DynamicTest.dynamicTest("Exported page does not log errors to js console " + endpoint, () -> {
|
||||
|
||||
String address = "http://" + webserver.getHost() + ":" + webserver.getMappedPort(8080)
|
||||
+ (endpoint.startsWith("/") ? endpoint : '/' + endpoint);
|
||||
System.out.println("GET: " + address);
|
||||
driver.get(address);
|
||||
|
||||
new WebDriverWait(driver, Duration.of(10, ChronoUnit.SECONDS)).until(
|
||||
webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
|
||||
Awaitility.await()
|
||||
.atMost(Duration.of(10, ChronoUnit.SECONDS))
|
||||
.until(() -> getElement(driver).map(WebElement::isDisplayed).orElse(false));
|
||||
|
||||
List<LogEntry> logs = new ArrayList<>();
|
||||
logs.addAll(driver.manage().logs().get(LogType.CLIENT).getAll());
|
||||
logs.addAll(driver.manage().logs().get(LogType.BROWSER).getAll());
|
||||
|
||||
assertNoLogs(logs);
|
||||
})
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Optional<WebElement> getElement(ChromeDriver driver) {
|
||||
try {
|
||||
return Optional.of(driver.findElement(By.className("load-in")));
|
||||
} catch (NoSuchElementException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoLogs(List<LogEntry> logs) {
|
||||
List<String> loggedLines = logs.stream()
|
||||
.map(log -> "\n" + log.getLevel().getName() + " " + log.getMessage())
|
||||
.toList();
|
||||
assertTrue(loggedLines.isEmpty(), () -> "Browser console included " + loggedLines.size() + " logs: " + loggedLines);
|
||||
}
|
||||
}
|
@ -87,7 +87,7 @@ class JSErrorRegressionTest {
|
||||
config.set(PluginSettings.FRONTEND_BETA, true);
|
||||
|
||||
// Avoid accidentally DDoS:ing head image service during tests.
|
||||
config.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "http://localhost:" + TEST_PORT_NUMBER + "/${playerUUID}/img/Flaticon_circle.png");
|
||||
config.set(DisplaySettings.PLAYER_HEAD_IMG_URL, "data:image/png;base64,AA==");
|
||||
|
||||
planSystem.enable();
|
||||
serverUUID = planSystem.getServerInfo().getServerUUID();
|
||||
|
@ -60,7 +60,7 @@ const LoadIn = ({children, duration}) => {
|
||||
return (
|
||||
<Transition in={visible} timeout={duration}>
|
||||
{state => (
|
||||
<div style={{
|
||||
<div className={"load-in"} style={{
|
||||
...defaultStyle,
|
||||
...transitionStyles[state]
|
||||
}}>
|
||||
|
@ -2,17 +2,22 @@ import React from 'react';
|
||||
import {Col, Row} from "react-bootstrap-v5";
|
||||
import JoinAddressGroupCard from "../../components/cards/server/graphs/JoinAddressGroupCard";
|
||||
import JoinAddressGraphCard from "../../components/cards/server/graphs/JoinAddressGraphCard";
|
||||
import LoadIn from "../../components/animation/LoadIn";
|
||||
|
||||
const NetworkJoinAddresses = () => {
|
||||
return (
|
||||
<Row>
|
||||
<Col lg={8}>
|
||||
<JoinAddressGraphCard identifier={undefined}/>
|
||||
</Col>
|
||||
<Col lg={4}>
|
||||
<JoinAddressGroupCard identifier={undefined}/>
|
||||
</Col>
|
||||
</Row>
|
||||
<LoadIn>
|
||||
<section className={"network_join_addresses"}>
|
||||
<Row>
|
||||
<Col lg={8}>
|
||||
<JoinAddressGraphCard identifier={undefined}/>
|
||||
</Col>
|
||||
<Col lg={4}>
|
||||
<JoinAddressGroupCard identifier={undefined}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</section>
|
||||
</LoadIn>
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -3,18 +3,23 @@ import {Col, Row} from "react-bootstrap-v5";
|
||||
import JoinAddressGroupCard from "../../components/cards/server/graphs/JoinAddressGroupCard";
|
||||
import JoinAddressGraphCard from "../../components/cards/server/graphs/JoinAddressGraphCard";
|
||||
import {useParams} from "react-router-dom";
|
||||
import LoadIn from "../../components/animation/LoadIn";
|
||||
|
||||
const ServerJoinAddresses = () => {
|
||||
const {identifier} = useParams();
|
||||
return (
|
||||
<Row>
|
||||
<Col lg={8}>
|
||||
<JoinAddressGraphCard identifier={identifier}/>
|
||||
</Col>
|
||||
<Col lg={4}>
|
||||
<JoinAddressGroupCard identifier={identifier}/>
|
||||
</Col>
|
||||
</Row>
|
||||
<LoadIn>
|
||||
<section className={"server_join_addresses"}>
|
||||
<Row>
|
||||
<Col lg={8}>
|
||||
<JoinAddressGraphCard identifier={identifier}/>
|
||||
</Col>
|
||||
<Col lg={4}>
|
||||
<JoinAddressGroupCard identifier={identifier}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</section>
|
||||
</LoadIn>
|
||||
)
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user