diff --git a/test/common.js b/test/common.js index b35116d9..12bf426e 100644 --- a/test/common.js +++ b/test/common.js @@ -33,3 +33,25 @@ export function testRoundTripJsonSerialisable(Class, tests) { } } } + + +/** + * Mark that this test takes a lot of time, or depends on a test that takes a + * lot of time. + */ +export function slowTest(test) { + if (process.env.FAST_TEST) { + test.skip(); + } + test.timeout(30000); +} + +/** + * Mark that this test depends on an external API and may be slow or flaky. + */ +export function externalTest(test) { + if (process.env.NO_EXTERNAL_TEST) { + test.skip(); + } + test.timeout(60000); +} diff --git a/test/controller/Controller.js b/test/controller/Controller.js index d2f014ca..c0fc29e6 100644 --- a/test/controller/Controller.js +++ b/test/controller/Controller.js @@ -12,6 +12,8 @@ import { addPluginConfigFields, } from "@clusterio/lib"; +import "../setup_logging.js"; + class MockEvent {} class MockInstanceConfig extends EventEmitter { diff --git a/test/controller/routes.js b/test/controller/routes.js index a15eccda..e86811e8 100644 --- a/test/controller/routes.js +++ b/test/controller/routes.js @@ -7,6 +7,8 @@ import { wait, expositionContentType } from "@clusterio/lib"; import * as routes from "@clusterio/controller/dist/node/src/routes.js"; import * as mock from "../mock.js"; +import "../setup_logging.js"; + describe("controller/src/routes", function() { let controller; let server; diff --git a/test/host.js b/test/host/Host.test.js similarity index 99% rename from test/host.js rename to test/host/Host.test.js index 4fafc52e..8332469a 100644 --- a/test/host.js +++ b/test/host/Host.test.js @@ -6,8 +6,9 @@ import * as lib from "@clusterio/lib"; import Host, { _discoverInstances } from "@clusterio/host/dist/node/src/Host.js"; import Instance from "@clusterio/host/dist/node/src/Instance.js"; import { HostConnector } from "@clusterio/host/dist/node/host.js"; +import "../setup_logging.js"; -describe("Host testing", function() { +describe("host/src/Host", function() { describe("discoverInstances()", function() { it("should discover test instance", async function() { const instancePath = path.join("test", "file", "instances"); diff --git a/test/host/Instance.js b/test/host/Instance.js index afefe99b..81511911 100644 --- a/test/host/Instance.js +++ b/test/host/Instance.js @@ -6,6 +6,8 @@ import { PlayerStats, wait } from "@clusterio/lib"; import Instance from "@clusterio/host/dist/node/src/Instance.js"; import { MockConnector, MockLogger, MockServer } from "../mock.js"; +import "../setup_logging.js"; + const addr = lib.Address.fromShorthand; diff --git a/test/host/server.js b/test/host/server.js index 60a0e681..dd4789dc 100644 --- a/test/host/server.js +++ b/test/host/server.js @@ -6,7 +6,8 @@ import path from "node:path"; import * as hostServer from "@clusterio/host/dist/node/src/server.js"; import { Link, wait } from "@clusterio/lib"; import { testLines } from "../lib/factorio/lines.js"; -import { slowTest, externalTest } from "../integration/index.js"; +import { slowTest, externalTest } from "../common.js"; +import "../setup_logging.js"; describe("host/server", function() { diff --git a/test/integration/clusterio.js b/test/integration/clusterio.js index b68f3809..01cd0681 100644 --- a/test/integration/clusterio.js +++ b/test/integration/clusterio.js @@ -10,11 +10,12 @@ import * as libBuildMod from "@clusterio/lib/build_mod.js"; import * as testStrings from "../lib/factorio/test_strings.js"; import { - TestControl, TestControlConnector, url, controlToken, slowTest, + TestControl, TestControlConnector, url, controlToken, execCtl, execCtlProcess, execController, execHost, sendRcon, getControl, spawnNode, instancesDir, factorioDir, databaseDir, controllerConfigPath, requiresFactorio, hasFactorio, } from "./index.js"; +import { slowTest } from "../common.js"; import { ControllerEcho, HostEchoReceived } from "../file/test_plugin/messages.js"; diff --git a/test/integration/index.js b/test/integration/index.js index 305d6769..48b018df 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -8,11 +8,13 @@ import util from "node:util"; import events from "node:events"; import * as lib from "@clusterio/lib"; -import { LineSplitter, ConsoleTransport, logger } from "@clusterio/lib"; +import { LineSplitter, logger } from "@clusterio/lib"; import { selectTargetCommand, initialize as initializeCtl } from "@clusterio/ctl"; import { _listFactorioVersions } from "@clusterio/host/dist/node/src/server.js"; +import "../setup_logging.js"; + // Make sure permissions from plugins are loaded import "../../plugins/global_chat/dist/node/index.js"; import "../../plugins/player_auth/dist/node/index.js"; @@ -117,25 +119,6 @@ export class TestHostConnector extends lib.WebSocketClientConnector { } } -// Mark that this test takes a lot of time, or depends on a test that takes a lot of time. -export function slowTest(test) { - - if (process.env.FAST_TEST) { - test.skip(); - } - - test.timeout(30000); -} - -// Mark that this test depends on an external API and may be slow or flaky. -export function externalTest(test) { - if (process.env.NO_EXTERNAL_TEST) { - test.skip(); - } - - test.timeout(60000); -} - // Mark that this test or suite of tests requires a factorio install to run. export function requiresFactorio(testOrSuite) { if (testOrSuite.skip) { @@ -316,13 +299,6 @@ before(async function() { console.log("SILENT_TEST is present in env, loggers after bootstrap will be muted."); } - // Some integration tests may cause log events - logger.add(new ConsoleTransport({ - level: "info", - format: new lib.TerminalFormat(), - filter: () => !silent, - })); - // If fast test is enabled then output that it is if (process.env.FAST_TEST) { diff --git a/test/integration/instance.js b/test/integration/instance.js index 8bcdec7d..e82d3bfb 100644 --- a/test/integration/instance.js +++ b/test/integration/instance.js @@ -3,9 +3,9 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; import fs from "node:fs/promises"; -import { testMatrix } from "../common.js"; +import { slowTest, testMatrix } from "../common.js"; import { - slowTest, exec, execCtl, execCtlProcess, sendRcon, getControl, + execCtl, execCtlProcess, sendRcon, getControl, requiresFactorio, hasFactorio, instancesDir, } from "./index.js"; diff --git a/test/integration/link.js b/test/integration/link.js index 53b3c76b..8bfdd211 100644 --- a/test/integration/link.js +++ b/test/integration/link.js @@ -3,9 +3,10 @@ import events from "node:events"; import jwt from "jsonwebtoken"; import { - TestControlConnector, TestHostConnector, TestControl, get, exec, url, controlToken, slowTest, + TestControlConnector, TestHostConnector, TestControl, url, controlToken, } from "./index.js"; import { ConnectionClosed, ProtocolError, PolicyViolation, AuthenticationFailed } from "@clusterio/lib"; +import { slowTest } from "../common.js"; let tokenHost = jwt.sign({ aud: "host", host: 0 }, Buffer.from("TestSecretDoNotUse", "base64")); diff --git a/test/integration/patch.js b/test/integration/patch.js index d222ff6d..8f04302a 100644 --- a/test/integration/patch.js +++ b/test/integration/patch.js @@ -6,7 +6,7 @@ import path from "node:path"; import { patch, SaveModule } from "@clusterio/host/dist/node/src/patch.js"; import * as lib from "@clusterio/lib"; -import { slowTest } from "./index.js"; +import { slowTest } from "../common.js"; // The server integration test is required to run before this one diff --git a/test/integration/server.js b/test/integration/server.js index f0e08c30..fe3d129b 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -8,7 +8,8 @@ import { InstanceManager } from "@clusterio/controller"; import { FactorioServer, _getFactorioVersion } from "@clusterio/host/dist/node/src/server.js"; import { logger } from "@clusterio/lib"; -import { slowTest, factorioDir, requiresFactorio } from "./index.js"; +import { factorioDir, requiresFactorio } from "./index.js"; +import { slowTest } from "../common.js"; describe("Integration of host/src/server", function() { diff --git a/test/lib/ModStore.test.js b/test/lib/ModStore.test.js index 32e88e5e..4c7d1b0b 100644 --- a/test/lib/ModStore.test.js +++ b/test/lib/ModStore.test.js @@ -8,7 +8,8 @@ import JSZip from "jszip"; // Added for creating mock zips const nativeFetch = global.fetch; import { ModStore, ModInfo, ModVersionEquality } from "@clusterio/lib"; // Adjust path based on compiled output -import { externalTest } from "../integration/index.js"; +import { externalTest } from "../common.js"; +import "../setup_logging.js"; const MODS_DIR = path.join("temp", "test", "mod_store", "mods"); const CACHE_FILE = path.join(MODS_DIR, "mod-info-cache.json"); diff --git a/test/lib/bootstrap.test.js b/test/lib/bootstrap.test.js index 065aecc4..a5d00b88 100644 --- a/test/lib/bootstrap.test.js +++ b/test/lib/bootstrap.test.js @@ -4,6 +4,8 @@ import path from "node:path"; import * as lib from "@clusterio/lib"; +import "../setup_logging.js"; + describe("lib/bootstrap", function() { describe("loadConfigFromArgs()", function() { const folder = path.join("temp", "test", "bootstrap"); diff --git a/test/lib/datastore.js b/test/lib/datastore.js index b4dc5cee..322450aa 100644 --- a/test/lib/datastore.js +++ b/test/lib/datastore.js @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; import fs from "node:fs/promises"; import path from "node:path"; +import "../setup_logging.js"; class MockDatastoreProvider extends lib.DatastoreProvider { constructor() { diff --git a/test/lib/external/FactorioVersions.test.js b/test/lib/external/FactorioVersions.test.js index f63554d9..b87d9016 100644 --- a/test/lib/external/FactorioVersions.test.js +++ b/test/lib/external/FactorioVersions.test.js @@ -2,7 +2,7 @@ import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { fetchFactorioVersions } from "@clusterio/lib"; -import { slowTest, externalTest } from "../../integration/index.js"; +import { slowTest, externalTest } from "../../common.js"; describe("FactorioVersions", function() { describe("fetchFactorioVersions", function() { diff --git a/test/lib/external/LatestReleases.test.js b/test/lib/external/LatestReleases.test.js index 686b6b52..951e9376 100644 --- a/test/lib/external/LatestReleases.test.js +++ b/test/lib/external/LatestReleases.test.js @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import { fetchLatestReleases, resolveReleaseChannel } from "@clusterio/lib"; -import { slowTest, externalTest } from "../../integration/index.js"; +import { slowTest, externalTest } from "../../common.js"; describe("LatestReleases", function() { describe("fetchLatestReleases", function() { diff --git a/test/lib/file_ops.js b/test/lib/file_ops.js index b338d927..dfaf905f 100644 --- a/test/lib/file_ops.js +++ b/test/lib/file_ops.js @@ -122,7 +122,8 @@ describe("lib/file_ops", function() { for (let i = 0; i < 20; i++) { writes.push(lib.safeOutputFile(target, `write ${i}`, "utf8")); } - await Promise.all(writes); + // Ignore errors from concurrently renaming onto the same file. + await Promise.allSettled(writes); await assertNoTemporary(target); assert.match(await fs.readFile(target, "utf8"), /^write \d+$/); }); diff --git a/test/lib/link/connector.js b/test/lib/link/connector.js index 851b9e78..7423cc70 100644 --- a/test/lib/link/connector.js +++ b/test/lib/link/connector.js @@ -1,8 +1,9 @@ import assert from "node:assert/strict"; import events from "node:events"; -import * as mock from "../../mock.js"; import * as lib from "@clusterio/lib"; +import * as mock from "../../mock.js"; +import "../../setup_logging.js"; describe("lib/link/connectors", function() { diff --git a/test/lib/link/link.js b/test/lib/link/link.js index 6519a08e..5a02dc10 100644 --- a/test/lib/link/link.js +++ b/test/lib/link/link.js @@ -3,6 +3,7 @@ import events from "node:events"; import * as lib from "@clusterio/lib"; import * as mock from "../../mock.js"; +import "../../setup_logging.js"; const addr = lib.Address.fromShorthand; diff --git a/test/lib/logging_utils.js b/test/lib/logging_utils.js index ba159555..054e49e4 100644 --- a/test/lib/logging_utils.js +++ b/test/lib/logging_utils.js @@ -4,6 +4,7 @@ import path from "node:path"; import { testLines } from "./factorio/lines.js"; import * as lib from "@clusterio/lib"; +import "../setup_logging.js"; describe("lib/logging_utils.js", function() { diff --git a/test/lib/rce_ops.js b/test/lib/rce_ops.js index 8ba32661..ae9942fb 100644 --- a/test/lib/rce_ops.js +++ b/test/lib/rce_ops.js @@ -1,5 +1,6 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; +import "../setup_logging.js"; describe("rce_ops", function() { describe("updatePackage", function() { diff --git a/test/lib/shared_commands.js b/test/lib/shared_commands.js index d40c27a0..740550ad 100644 --- a/test/lib/shared_commands.js +++ b/test/lib/shared_commands.js @@ -3,7 +3,8 @@ import fs from "node:fs/promises"; import path from "node:path"; import * as lib from "@clusterio/lib"; -import { slowTest } from "../integration/index.js"; +import { slowTest } from "../common.js"; +import "../setup_logging.js"; describe("lib/shared_commands", function() { diff --git a/test/lib/subscriptions.test.js b/test/lib/subscriptions.test.js index 97e7f943..780d58b8 100644 --- a/test/lib/subscriptions.test.js +++ b/test/lib/subscriptions.test.js @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; import { MockController, MockConnector, MockControl } from "../mock.js"; import { testMatrix, testRoundTripJsonSerialisable } from "../common.js"; +import "../setup_logging.js"; const addr = lib.Address.fromShorthand; diff --git a/test/messages/controller.test.js b/test/messages/controller.test.js index d876a60c..b7bd90cc 100644 --- a/test/messages/controller.test.js +++ b/test/messages/controller.test.js @@ -6,6 +6,7 @@ import * as lib from "@clusterio/lib"; import { Controller, ControlConnection } from "@clusterio/controller"; import { testMatrix, testRoundTripJsonSerialisable } from "../common.js"; +import "../setup_logging.js"; describe("messages/controller", function() { /** @type {Controller} */ diff --git a/test/messages/host.test.js b/test/messages/host.test.js index fe40256a..25310748 100644 --- a/test/messages/host.test.js +++ b/test/messages/host.test.js @@ -3,6 +3,7 @@ import * as lib from "@clusterio/lib"; import { Host } from "@clusterio/host"; import { testMatrix, testRoundTripJsonSerialisable } from "../common.js"; +import "../setup_logging.js"; describe("messages/host", function() { /** @type {Host} */ diff --git a/test/messages/mod.test.js b/test/messages/mod.test.js index 7a80b2eb..486a6a2a 100644 --- a/test/messages/mod.test.js +++ b/test/messages/mod.test.js @@ -2,11 +2,10 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; import { ModDependencyResolveRequest, ModDependency, ModInfo } from "@clusterio/lib"; - -import { testMatrix, testRoundTripJsonSerialisable } from "../common.js"; - import { Controller, ControlConnection } from "@clusterio/controller"; -import { externalTest } from "../integration/index.js"; + +import { externalTest, testMatrix, testRoundTripJsonSerialisable } from "../common.js"; +import "../setup_logging.js"; describe("messages/mod", function() { /** @type {Controller} */ diff --git a/test/messages/plugin.test.js b/test/messages/plugin.test.js index 45e55048..38d03b9a 100644 --- a/test/messages/plugin.test.js +++ b/test/messages/plugin.test.js @@ -4,6 +4,8 @@ import * as lib from "@clusterio/lib"; import { Controller, ControlConnection } from "@clusterio/controller"; import { Host } from "@clusterio/host"; +import "../setup_logging.js"; + describe("messages/plugin", function() { /** @type {Host} */ let host; diff --git a/test/setup_logging.js b/test/setup_logging.js new file mode 100644 index 00000000..f5d8cec4 --- /dev/null +++ b/test/setup_logging.js @@ -0,0 +1,15 @@ +import { ConsoleTransport, TerminalFormat, logger } from "@clusterio/lib"; + +// Some integration tests may cause log events, import this file for such tests +// to avoid getting the "Attempt to write logs with no transports" warning when +// running tests individually. + +before(function() { + const silent = process.env.SILENT_TEST; + + logger.add(new ConsoleTransport({ + level: "info", + format: new TerminalFormat(), + filter: () => !silent, + })); +});