@serverkgg/bridge 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rules/package.md +1 -0
- package/src/cli/validate.test.ts +429 -3
- package/src/cli/validate.ts +225 -1
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest.test.ts +79 -0
- package/src/manifest/manifest.ts +5 -0
- package/src/manifest/steam.ts +14 -0
- package/src/steam/steamcmd.test.ts +367 -1
- package/src/steam/steamcmd.ts +154 -18
package/src/manifest/index.ts
CHANGED
|
@@ -931,6 +931,85 @@ describe("presence", () => {
|
|
|
931
931
|
});
|
|
932
932
|
});
|
|
933
933
|
|
|
934
|
+
describe("steam", () => {
|
|
935
|
+
it("is optional, so a game that declares none parses", () => {
|
|
936
|
+
const result = gameManifestSchema.safeParse(base());
|
|
937
|
+
|
|
938
|
+
expect(result.success).toBe(true);
|
|
939
|
+
expect(result.success && result.data.steam).toBeUndefined();
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
it("accepts the server app id", () => {
|
|
943
|
+
const result = gameManifestSchema.safeParse({
|
|
944
|
+
...base(),
|
|
945
|
+
steam: {
|
|
946
|
+
appId: 896_660,
|
|
947
|
+
},
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
expect(result.success).toBe(true);
|
|
951
|
+
expect(result.success && result.data.steam).toEqual({
|
|
952
|
+
appId: 896_660,
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
it("accepts the variable that holds the Steam branch", () => {
|
|
957
|
+
const result = gameManifestSchema.safeParse({
|
|
958
|
+
...base(),
|
|
959
|
+
steam: {
|
|
960
|
+
appId: 896_660,
|
|
961
|
+
branchVariable: "VALHEIM_BRANCH",
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
expect(result.success).toBe(true);
|
|
966
|
+
expect(result.success && result.data.steam).toEqual({
|
|
967
|
+
appId: 896_660,
|
|
968
|
+
branchVariable: "VALHEIM_BRANCH",
|
|
969
|
+
});
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it("refuses a branch variable that is not an environment key", () => {
|
|
973
|
+
const result = gameManifestSchema.safeParse({
|
|
974
|
+
...base(),
|
|
975
|
+
steam: {
|
|
976
|
+
appId: 896_660,
|
|
977
|
+
branchVariable: "valheim-branch",
|
|
978
|
+
},
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
expect(result.success).toBe(false);
|
|
982
|
+
expect(result.error && z.prettifyError(result.error)).toContain("must be SCREAMING_SNAKE_CASE");
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
for (const appId of [
|
|
986
|
+
0,
|
|
987
|
+
-1,
|
|
988
|
+
2.5,
|
|
989
|
+
"258550",
|
|
990
|
+
]) {
|
|
991
|
+
it(`refuses ${JSON.stringify(appId)} as an app id`, () => {
|
|
992
|
+
const result = gameManifestSchema.safeParse({
|
|
993
|
+
...base(),
|
|
994
|
+
steam: {
|
|
995
|
+
appId,
|
|
996
|
+
},
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
expect(result.success).toBe(false);
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
it("refuses a block with no app id", () => {
|
|
1004
|
+
const result = gameManifestSchema.safeParse({
|
|
1005
|
+
...base(),
|
|
1006
|
+
steam: {},
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
expect(result.success).toBe(false);
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
|
|
934
1013
|
describe("container runtime", () => {
|
|
935
1014
|
it("materializes the defaults when the manifest declares no runtime", () => {
|
|
936
1015
|
const manifest = manifestSchema.parse(base());
|
package/src/manifest/manifest.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
zSlug,
|
|
23
23
|
} from "./primitives";
|
|
24
24
|
import { ManifestPlatform, manifestRuntimeSchema, WINE_MIN_SHM_MB } from "./runtime";
|
|
25
|
+
import { manifestSteamSchema } from "./steam";
|
|
25
26
|
|
|
26
27
|
export const MANIFEST_SCHEMA_VERSION = "serverk.gg/v1";
|
|
27
28
|
|
|
@@ -825,6 +826,10 @@ export const gameManifestSchema = z
|
|
|
825
826
|
secrets: z.array(manifestSecretSchema).max(16).default([]),
|
|
826
827
|
files: manifestFilesSchema.prefault({}),
|
|
827
828
|
presence: manifestPresenceSchema.optional(),
|
|
829
|
+
steam: manifestSteamSchema.optional().meta({
|
|
830
|
+
description:
|
|
831
|
+
"The Steam app behind this game. Declare it when steamcmd installs the server, so the platform sees when a newer game version is out.",
|
|
832
|
+
}),
|
|
828
833
|
})
|
|
829
834
|
.check((ctx) => {
|
|
830
835
|
if (ctx.issues.length > 0) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { zEnvKey } from "./primitives";
|
|
3
|
+
|
|
4
|
+
export const manifestSteamSchema = z.object({
|
|
5
|
+
appId: z.int().positive().meta({
|
|
6
|
+
description: "Steam app id of the dedicated server, the one steamcmd installs with app_update.",
|
|
7
|
+
}),
|
|
8
|
+
branchVariable: zEnvKey.optional().meta({
|
|
9
|
+
description:
|
|
10
|
+
"The server variable that holds the Steam branch the customer picked. Omit it when the package installs the public branch only.",
|
|
11
|
+
}),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type ManifestSteam = z.infer<typeof manifestSteamSchema>;
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import type { BridgeContext, BridgeExecResult } from "../context";
|
|
3
|
+
import type { BridgeValues } from "../core";
|
|
4
|
+
import {
|
|
5
|
+
createSteamcmd,
|
|
6
|
+
SteamcmdFailure,
|
|
7
|
+
steamcmdArgv,
|
|
8
|
+
steamcmdFailureOf,
|
|
9
|
+
steamcmdFailureText,
|
|
10
|
+
steamcmdRetryable,
|
|
11
|
+
steamcmdScript,
|
|
12
|
+
steamcmdUpdateArgs,
|
|
13
|
+
} from "./steamcmd";
|
|
3
14
|
import { SteamcmdLoginKind, steamcmdLoginArgs } from "./steamcmdLogin";
|
|
4
15
|
import { SteamcmdPlatform } from "./steamcmdPlatform";
|
|
5
16
|
|
|
@@ -8,6 +19,86 @@ const OPTIONS = {
|
|
|
8
19
|
label: "palworld",
|
|
9
20
|
};
|
|
10
21
|
|
|
22
|
+
const MANIFEST = [
|
|
23
|
+
'"AppState"',
|
|
24
|
+
"{",
|
|
25
|
+
'\t"appid"\t\t"2394010"',
|
|
26
|
+
'\t"buildid"\t\t"19582821"',
|
|
27
|
+
"}",
|
|
28
|
+
].join("\n");
|
|
29
|
+
|
|
30
|
+
const SUCCESS: BridgeExecResult = {
|
|
31
|
+
stdout: "Success! App '2394010' fully installed.",
|
|
32
|
+
stderr: "",
|
|
33
|
+
code: 0,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
interface Logged {
|
|
37
|
+
message: string;
|
|
38
|
+
fields?: BridgeValues;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const resultOf = (stdout: string): BridgeExecResult => {
|
|
42
|
+
return {
|
|
43
|
+
stdout,
|
|
44
|
+
stderr: "",
|
|
45
|
+
code: 8,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const contextWith = (answers: BridgeExecResult[], files: Record<string, string>) => {
|
|
50
|
+
const commands: string[][] = [];
|
|
51
|
+
const logs: Logged[] = [];
|
|
52
|
+
|
|
53
|
+
const log = Object.assign(
|
|
54
|
+
(message: string, fields?: BridgeValues) => {
|
|
55
|
+
logs.push({
|
|
56
|
+
message,
|
|
57
|
+
fields,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
warn(message: string, fields?: BridgeValues) {
|
|
62
|
+
logs.push({
|
|
63
|
+
message,
|
|
64
|
+
fields,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const context = {
|
|
71
|
+
async exec(command: string[]) {
|
|
72
|
+
commands.push(command);
|
|
73
|
+
|
|
74
|
+
if (command[0] === "pwd") {
|
|
75
|
+
return {
|
|
76
|
+
stdout: "/home/container\n",
|
|
77
|
+
stderr: "",
|
|
78
|
+
code: 0,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return answers.shift() ?? SUCCESS;
|
|
83
|
+
},
|
|
84
|
+
files: {
|
|
85
|
+
async exists(path: string) {
|
|
86
|
+
return path in files;
|
|
87
|
+
},
|
|
88
|
+
async read(path: string) {
|
|
89
|
+
return files[path] ?? "";
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
log,
|
|
93
|
+
} as unknown as BridgeContext;
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
context,
|
|
97
|
+
commands,
|
|
98
|
+
logs,
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
11
102
|
describe("steamcmdLoginArgs", () => {
|
|
12
103
|
it("logs in anonymously by default", () => {
|
|
13
104
|
expect(steamcmdLoginArgs()).toEqual([
|
|
@@ -85,12 +176,26 @@ describe("steamcmdArgv", () => {
|
|
|
85
176
|
});
|
|
86
177
|
|
|
87
178
|
describe("steamcmdUpdateArgs", () => {
|
|
179
|
+
it("refreshes the app info before the update", () => {
|
|
180
|
+
const args = steamcmdUpdateArgs("258550", {
|
|
181
|
+
validate: false,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
expect(args.slice(0, 2)).toEqual([
|
|
185
|
+
"+app_info_update",
|
|
186
|
+
"1",
|
|
187
|
+
]);
|
|
188
|
+
expect(args.indexOf("+app_info_update")).toBeLessThan(args.indexOf("+app_update"));
|
|
189
|
+
});
|
|
190
|
+
|
|
88
191
|
it("updates without validating by default", () => {
|
|
89
192
|
expect(
|
|
90
193
|
steamcmdUpdateArgs("258550", {
|
|
91
194
|
validate: false,
|
|
92
195
|
}),
|
|
93
196
|
).toEqual([
|
|
197
|
+
"+app_info_update",
|
|
198
|
+
"1",
|
|
94
199
|
"+app_update",
|
|
95
200
|
"258550",
|
|
96
201
|
]);
|
|
@@ -102,6 +207,8 @@ describe("steamcmdUpdateArgs", () => {
|
|
|
102
207
|
validate: true,
|
|
103
208
|
}),
|
|
104
209
|
).toEqual([
|
|
210
|
+
"+app_info_update",
|
|
211
|
+
"1",
|
|
105
212
|
"+app_update",
|
|
106
213
|
"258550",
|
|
107
214
|
"validate",
|
|
@@ -116,6 +223,8 @@ describe("steamcmdUpdateArgs", () => {
|
|
|
116
223
|
branchPassword: "shh",
|
|
117
224
|
}),
|
|
118
225
|
).toEqual([
|
|
226
|
+
"+app_info_update",
|
|
227
|
+
"1",
|
|
119
228
|
"+app_update",
|
|
120
229
|
"90",
|
|
121
230
|
"-beta",
|
|
@@ -133,6 +242,8 @@ describe("steamcmdUpdateArgs", () => {
|
|
|
133
242
|
branchPassword: "shh",
|
|
134
243
|
}),
|
|
135
244
|
).toEqual([
|
|
245
|
+
"+app_info_update",
|
|
246
|
+
"1",
|
|
136
247
|
"+app_update",
|
|
137
248
|
"90",
|
|
138
249
|
]);
|
|
@@ -148,6 +259,8 @@ describe("steamcmdUpdateArgs", () => {
|
|
|
148
259
|
],
|
|
149
260
|
}),
|
|
150
261
|
).toEqual([
|
|
262
|
+
"+app_info_update",
|
|
263
|
+
"1",
|
|
151
264
|
"+app_update",
|
|
152
265
|
"376030",
|
|
153
266
|
"-language",
|
|
@@ -156,7 +269,142 @@ describe("steamcmdUpdateArgs", () => {
|
|
|
156
269
|
});
|
|
157
270
|
});
|
|
158
271
|
|
|
272
|
+
const FAILURE_CASES = [
|
|
273
|
+
{
|
|
274
|
+
output: "Error! App '2394010' state is 0x202 after update job.",
|
|
275
|
+
failure: SteamcmdFailure.DiskFull,
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
output: "Error! App '2394010' state is 0x212 after update job.",
|
|
279
|
+
failure: SteamcmdFailure.DiskFull,
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
output: "Invalid platform",
|
|
283
|
+
failure: SteamcmdFailure.InvalidPlatform,
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
output: "No subscription",
|
|
287
|
+
failure: SteamcmdFailure.NoSubscription,
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
output: "Password check for AppId 896660",
|
|
291
|
+
failure: SteamcmdFailure.BranchPassword,
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
output: "Error! State is 0x402 after update job.",
|
|
295
|
+
failure: SteamcmdFailure.Transient,
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
output: "Error! State is 0x602 after update job.",
|
|
299
|
+
failure: SteamcmdFailure.Transient,
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
output: "Error! App '2394010' state is 0x606 after update job.",
|
|
303
|
+
failure: SteamcmdFailure.Transient,
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
output: "Error! App '232250' state is 0x626 after update job.",
|
|
307
|
+
failure: SteamcmdFailure.Transient,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
output: "Error! App '317670' state is 0x6A6 after update job.",
|
|
311
|
+
failure: SteamcmdFailure.Transient,
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
output: "Missing configuration",
|
|
315
|
+
failure: SteamcmdFailure.Transient,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
output: "Update state (0x61) downloading, progress: 1.11 (127644881 / 11530459441)",
|
|
319
|
+
failure: SteamcmdFailure.Unknown,
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
output: "",
|
|
323
|
+
failure: SteamcmdFailure.Unknown,
|
|
324
|
+
},
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
describe("steamcmdFailureOf", () => {
|
|
328
|
+
for (const item of FAILURE_CASES) {
|
|
329
|
+
it(`reads ${JSON.stringify(item.output)} as ${item.failure}`, () => {
|
|
330
|
+
expect(steamcmdFailureOf(resultOf(item.output))).toBe(item.failure);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
it("reads the code from stderr too", () => {
|
|
335
|
+
expect(
|
|
336
|
+
steamcmdFailureOf({
|
|
337
|
+
stdout: "",
|
|
338
|
+
stderr: "Error! App '2394010' state is 0x212 after update job.",
|
|
339
|
+
code: 8,
|
|
340
|
+
}),
|
|
341
|
+
).toBe(SteamcmdFailure.DiskFull);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("puts a full disk ahead of a transient code in the same output", () => {
|
|
345
|
+
expect(
|
|
346
|
+
steamcmdFailureOf(
|
|
347
|
+
resultOf(
|
|
348
|
+
[
|
|
349
|
+
"Error! State is 0x602 after update job.",
|
|
350
|
+
"Error! App '2394010' state is 0x202 after update job.",
|
|
351
|
+
].join("\n"),
|
|
352
|
+
),
|
|
353
|
+
),
|
|
354
|
+
).toBe(SteamcmdFailure.DiskFull);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const RETRY_CASES = [
|
|
359
|
+
{
|
|
360
|
+
failure: SteamcmdFailure.DiskFull,
|
|
361
|
+
retryable: false,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
failure: SteamcmdFailure.InvalidPlatform,
|
|
365
|
+
retryable: false,
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
failure: SteamcmdFailure.NoSubscription,
|
|
369
|
+
retryable: false,
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
failure: SteamcmdFailure.BranchPassword,
|
|
373
|
+
retryable: false,
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
failure: SteamcmdFailure.Transient,
|
|
377
|
+
retryable: true,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
failure: SteamcmdFailure.Unknown,
|
|
381
|
+
retryable: true,
|
|
382
|
+
},
|
|
383
|
+
];
|
|
384
|
+
|
|
385
|
+
describe("steamcmdRetryable", () => {
|
|
386
|
+
for (const item of RETRY_CASES) {
|
|
387
|
+
it(`${item.retryable ? "retries" : "does not retry"} a ${item.failure} failure`, () => {
|
|
388
|
+
expect(steamcmdRetryable(item.failure)).toBe(item.retryable);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
159
393
|
describe("steamcmdFailureText", () => {
|
|
394
|
+
it("tells the owner to free space or move up a plan when the disk is full", () => {
|
|
395
|
+
expect(steamcmdFailureText(resultOf("Error! App '258550' state is 0x202 after update job."), "rust")).toEqual({
|
|
396
|
+
ar: "امتلأت مساحة سيرفرك، فتعذّر تنزيل rust من Steam. احذف الملفات التي لا تحتاجها من صفحة الملفات أو انتقل إلى باقة أكبر، ثم جرب مرة ثانية.",
|
|
397
|
+
en: "Your server is out of space, so we couldn't download rust from Steam. Delete files you don't need on the Files page or move to a larger plan, then try again.",
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("says the branch password is wrong and where to fix it", () => {
|
|
402
|
+
expect(steamcmdFailureText(resultOf("Password check for AppId 896660"), "valheim")).toEqual({
|
|
403
|
+
ar: "كلمة مرور الفرع على Steam غير صحيحة، فتعذّر تنزيل valheim. صحّحها من الإعدادات.",
|
|
404
|
+
en: "The Steam branch password is wrong, so we couldn't download valheim. Fix it in the settings.",
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
160
408
|
it("says the download account does not own the app when steam answers no subscription", () => {
|
|
161
409
|
expect(
|
|
162
410
|
steamcmdFailureText(
|
|
@@ -186,3 +434,121 @@ describe("steamcmdFailureText", () => {
|
|
|
186
434
|
});
|
|
187
435
|
});
|
|
188
436
|
});
|
|
437
|
+
|
|
438
|
+
describe("createSteamcmd", () => {
|
|
439
|
+
it("stops at the first failure a retry cannot fix", async () => {
|
|
440
|
+
const { context, commands } = contextWith(
|
|
441
|
+
[
|
|
442
|
+
resultOf("Error! App '2394010' state is 0x202 after update job."),
|
|
443
|
+
],
|
|
444
|
+
{},
|
|
445
|
+
);
|
|
446
|
+
const steamcmd = createSteamcmd(context, OPTIONS);
|
|
447
|
+
|
|
448
|
+
await expect(
|
|
449
|
+
steamcmd.run([
|
|
450
|
+
"+app_update",
|
|
451
|
+
"2394010",
|
|
452
|
+
]),
|
|
453
|
+
).rejects.toThrow(
|
|
454
|
+
"Your server is out of space, so we couldn't download palworld from Steam. Delete files you don't need on the Files page or move to a larger plan, then try again.",
|
|
455
|
+
);
|
|
456
|
+
expect(commands.filter((command) => command[0] !== "pwd")).toHaveLength(1);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it("clears the cached app info, updates, then logs the installed build", async () => {
|
|
460
|
+
const { context, commands, logs } = contextWith([], {
|
|
461
|
+
".steamcmd": "",
|
|
462
|
+
".steam": "",
|
|
463
|
+
"steamapps/appmanifest_2394010.acf": MANIFEST,
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
await createSteamcmd(context, OPTIONS).update({
|
|
467
|
+
validate: false,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
expect(commands).toEqual([
|
|
471
|
+
[
|
|
472
|
+
"find",
|
|
473
|
+
".steamcmd",
|
|
474
|
+
".steam",
|
|
475
|
+
"-type",
|
|
476
|
+
"f",
|
|
477
|
+
"-name",
|
|
478
|
+
"appinfo.vdf",
|
|
479
|
+
"-delete",
|
|
480
|
+
],
|
|
481
|
+
[
|
|
482
|
+
"pwd",
|
|
483
|
+
],
|
|
484
|
+
[
|
|
485
|
+
"./.steamcmd/steamcmd.sh",
|
|
486
|
+
"+force_install_dir",
|
|
487
|
+
"/home/container",
|
|
488
|
+
"+login",
|
|
489
|
+
"anonymous",
|
|
490
|
+
"+app_info_update",
|
|
491
|
+
"1",
|
|
492
|
+
"+app_update",
|
|
493
|
+
"2394010",
|
|
494
|
+
"+quit",
|
|
495
|
+
],
|
|
496
|
+
]);
|
|
497
|
+
expect(logs).toEqual([
|
|
498
|
+
{
|
|
499
|
+
message: "steamcmd finished the update",
|
|
500
|
+
fields: {
|
|
501
|
+
app: "2394010",
|
|
502
|
+
build: "19582821",
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
]);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it("skips clearing the app info when no steam directory is there yet", async () => {
|
|
509
|
+
const { context, commands, logs } = contextWith([], {});
|
|
510
|
+
|
|
511
|
+
await createSteamcmd(context, OPTIONS).update({
|
|
512
|
+
validate: false,
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
expect(commands.map((command) => command[0])).toEqual([
|
|
516
|
+
"pwd",
|
|
517
|
+
"./.steamcmd/steamcmd.sh",
|
|
518
|
+
]);
|
|
519
|
+
expect(logs).toEqual([
|
|
520
|
+
{
|
|
521
|
+
message: "steamcmd finished the update",
|
|
522
|
+
fields: {
|
|
523
|
+
app: "2394010",
|
|
524
|
+
build: null,
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
]);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it("updates anyway when the app info cannot be cleared", async () => {
|
|
531
|
+
const { context, commands, logs } = contextWith(
|
|
532
|
+
[
|
|
533
|
+
resultOf("find: permission denied"),
|
|
534
|
+
],
|
|
535
|
+
{
|
|
536
|
+
".steamcmd": "",
|
|
537
|
+
},
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
await createSteamcmd(context, OPTIONS).update({
|
|
541
|
+
validate: false,
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
expect(commands.map((command) => command[0])).toEqual([
|
|
545
|
+
"find",
|
|
546
|
+
"pwd",
|
|
547
|
+
"./.steamcmd/steamcmd.sh",
|
|
548
|
+
]);
|
|
549
|
+
expect(logs.map((entry) => entry.message)).toEqual([
|
|
550
|
+
"the cached steam app info could not be cleared, updating anyway",
|
|
551
|
+
"steamcmd finished the update",
|
|
552
|
+
]);
|
|
553
|
+
});
|
|
554
|
+
});
|