Repository navigation
Conversation
added 5 commits
October 22, 2026 06:49
…e suite The full Plugwright suite only runs on 1.21.8, so nothing proved that the plugin loads and answers on the versions it claims to support. The oldest Paper builds need a few things the tooling does not give them per environment, and this wires those up: - a launcher script per version, so the server runs on the JDK that version needs and the legacy CraftBukkit builds do not see the --nogui flag they reject - the newest Paper build per version, because the oldest one the API lists for 1.8.8 and 1.12.2 is a paperclip jar that fetches the vanilla server jar from a URL Mojang retired - use-native-transport=false for 1.8.8, whose Netty 4.0 cannot use direct buffers on a Java 11 JVM - EssentialsX 2.20.1 for the legacy versions, because 2.21 and newer need an Adventure API that Paper only ships from 1.18 on 1.12.2 joins the supported versions list on Java 11.
added 4 commits
October 22, 2026 12:41
The plugin reads four folders under plugins/Guilds when it starts, and the recovery work writes copies of unreadable files into a fifth one. Nothing proved that a file in the backup directory stays out of the plugin's records on a real server, where the reading happens at startup and the versions differ. Two guild files are staged into each smoke environment: one in the data folder, which the plugin has to load, and one in the backup directory, which it has to leave alone. Both are complete, valid guild records, so a plugin that read the wrong folder would load them. The smoke spec asserts both. The 26.3 environment has no bot to ask, so its server-level check asks the console instead.
The coverage inventory now counts 162 tests across 14 spec files, which is what the branches add up to. The section headings carry the merged numbers, and the section for the startup-loading spec is a placeholder: its table belongs to the pull request that adds the spec file.
A bot the server kicked is reported as "the connection had already ended (socketClosed)", which says nothing about what the server objected to. The kick carries a reason — "Flying is not enabled on this server", for a bot a teleport left in mid-air — and the end event overwrites it with the fact that the socket closed. Keeping the two apart makes the next occurrence readable.
Paper refuses a player whose client reports that it is not on the ground for 80 ticks, which is four seconds, unless the server allows flight. The homes spec teleports its bot into the air and then waits out a cooldown, and the server kicked the bot with "Flying is not enabled on this server" while it waited: the bot's socket was already closed when the command was about to be sent. The suite drives a throwaway server, so that server allows flight. Nothing in a test changes, and the plugin is not involved.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was missing
The E2E suite had exactly one environment, on 1.21.8, so nothing ran against the versions the plugin claims to support. The tooling could not have done it as it stood, and the two blockers are worth writing down because neither is obvious from the error you get.
Plugwright's local mode starts the server with the JVM of the project's Java toolchain, which is one setting for the whole build. A Paper 1.8.8 server does not run on Java 21.
Plugwright's provision task downloads the oldest build the Paper API lists for a version. For 1.8.8 and 1.12.2 that build is a paperclip jar whose patch data points at a Mojang URL that no longer serves the vanilla server jar, so the server exits before it loads a plugin:
With the download fixed and the server on Java 11, every connection the server accepted died on the socket:
That one is Netty 4.0.23, which 1.8.8 ships. It decides whether it can use direct buffers by reading the address of a heap buffer, and on Java 9 and later that address no longer reads as zero, so it gives up on the unsafe path. Without it the native transport cannot work.
What this adds
A smoke suite,
src/test/e2e/tests/smoke.spec.ts, that runs the same plugin, the same staged config and the same three dependencies on every supported version. Seven tests: the plugin and its hard dependencies enabled, Vault's economy and permission providers registered, the economy moving money, a command answering, a guild being created, and the two the recovery work needs. It is much smaller than the full suite on purpose, since the full suite is written against a modern server.Six environments in
build.gradle.kts, one per version:smoke-1.8.8smoke-1.12.2smoke-1.16.5smoke-1.21.8smoke-26.1.2smoke-26.3Three things had to be worked around per environment, all in the build script:
--noguiflag the runner always passes, which the CraftBukkit builds on 1.8.8 and 1.12.2 reject as an unknown option.use-native-transport=falseinserver.propertiesfor 1.8.8, which puts it on the NIO transport every Windows server uses.The legacy environments also run EssentialsX 2.20.1 rather than 2.22.0. EssentialsX 2.21 and newer need an Adventure API that Paper only started shipping with 1.18, and on 1.16.5 the plugin fails to enable with
NoClassDefFoundError: net/kyori/adventure/text/minimessage/tag/resolver/TagResolver.1.12.2 joins
supportedMinecraftVersionson Java 11, sorunServer1_12_2exists as well.Results
Ten is three preflight tests plus seven smoke tests. The whole run took 4m41s.
151 tests: 149 passed, 0 failed, 2 skipped, in 7m05s. That is the 141 existing tests, the 3 preflight tests and the 7 smoke tests. The two that are skipped are the recovery checks below, which have nothing staged to look at on the local environment.
Both succeeded.
checkincludes the 1.8.8 Material probe, which still compiles two Material constants against the 1.8.8 API.Compatibility
Nothing under
src/mainchanged. The plugin still targets Java 11 bytecode, the Material probe still runs, and no API, dependency or configuration key was touched. The environments differ only in the server they run against, the JDK that server runs on, and the EssentialsX build on the three legacy ones.The smoke spec runs on the 1.21.8 environment too, so a smoke failure on the current version is as loud as one on 1.8.8.
Limitations
26.3 has no bot-driven test.
minecraft-data, the protocol table mineflayer reads, has no entry for 26.3, and the server refuses a 26.1 client as an outdated one. That environment gets a server-level check instead: it starts the server and asserts that Guilds and its hard dependencies enabled, that Guilds did not disable itself, and that it found the economy and the permission provider. It cannot prove that the command layer works, because that needs a player. 26.1.2 shares the 26.1 protocol, which is the newest one minecraft-data knows, so the bot connects to that one.The 141 full-suite tests still only run on 1.21.8. The smoke suite proves the plugin loads and answers on the old versions, not that every feature works there.
The legacy environments start the server through a shell script, so they do not run on Windows.
A new
smokejob in.github/workflows/e2e.ymlruns the smoke suite on pull requests. The existing job is unchanged.The recovery path
The plugin reads four folders under
plugins/Guildswhen it starts:data,arenas,challengesandcooldowns. The recovery work writes copies of files it could not read into a fifth one,plugins/Guilds/backups/corrupt/<timestamp>/<data-type>/. The unit tests behind that work prove the provider does not enumerate the backup directory. They cannot prove it on a real server, where the reading happens during startup and where a 1.8.8 server behaves differently from a 1.21.8 one.Two guild files are staged into each smoke environment, both complete and valid guild records:
plugins/Guilds/data/8d3f1a67-….jsonplugins/Guilds/backups/corrupt/20240101-000000/guilds/1f6b9c2e-….jsonThe smoke spec asserts both, so a plugin that read the wrong folder would fail on every version. The 26.3 environment has no bot to ask, so its server-level check asks the console instead: the guild in the backup directory has to be unknown to the plugin, and the guild in the data folder has to be known to it.
The local environment gets neither file. A guild in its data folder would change what the full suite sees, so the two checks are restricted to the smoke environments and are reported as skipped on the local one. A new smoke environment has to be added to
SMOKE_ENVIRONMENTSintests/smoke.spec.tsas well, or those two checks are skipped on it.The storage changes in flight were checked against this suite on a throwaway copy of the branch that carries them, with this build script and these specs on top:
The shared helper
CorruptDataBackupusesjava.io,java.nio.file,java.securityandjava.timeonly. Every one of those APIs is in Java 8, and the project compiles it to Java 11 bytecode, so it runs on the 1.8.8 server's Java 11 JVM like the rest of the plugin.The coverage inventory,
docs/e2e-coverage.md, now carries the merged totals: 162 tests across 14spec files. The section headings hold the merged numbers, and the section for the startup-loading
spec is a heading with a note, because its table belongs to the pull request that adds the spec
file.
A flaky test in the suite
homes.spec.tsfails on about half the open pull requests, and on master itself in run37211243837. The bot's socket is already closed when the command is about to be sent, and the
server log says why:
The test teleports the bot to a spot in mid-air and then waits out a cooldown. Paper refuses a
player whose client reports that it is not on the ground for 80 ticks, which is four seconds,
unless the server allows flight:
MinecraftServer.isFlightAllowed()is what makes Paper skip thecheck. The suite drives a throwaway server, so that server now allows flight. Nothing in a test
changes, and the plugin is not involved.
This is not a keepalive problem. The runner has none for an idle bot, and a bot the client gives
up on ends with
keepAliveErrorrather than with a closed socket. The socket is closed by theserver.
Two smaller things go with it. A kicked bot now reports the reason the server gave instead of
"the connection had already ended (socketClosed)", because the end event used to overwrite the
kick reason with the fact that the socket closed. And the 1.8.8 smoke environment keeps its own
server property,
use-native-transport=false, which this change moves next to the new one.The homes spec passes with the fix in place: three runs in a row, 11 of 11 each time, including
"a second teleport home cannot happen until the cooldown expires".
Master's own failure is a separate thing. There the server was 64 ticks behind, the "blocked"
command reached it 3.2 seconds late, and the three-second cooldown of the time had expired
before the command was processed, so the server correctly teleported the player. The staged
config now uses fifteen seconds for the cooldowns, with a comment saying why.