Class ScriptedGameHost
- Namespace
- Valheim.Testing.GameSessions
- Assembly
- Valheim.Testing.GameSessions.dll
The shared implementation: every operation is a fixed script run through the host's shell, so local, SSH and container hosts behave alike and differ only in how the shell is started and how the ValheimCLI port is reached.
A script travels on standard input, never on a command line: a small fixed wrapper on the host reads it, writes it to a temporary file, runs it and reports its exit code on its own line of stderr. That report, not the transport's exit status, is the script's exit code, so a Windows host whose login shell is PowerShell (which reports only 0 or 1) still returns the real one. Without the report the outcome is a transport failure or unknown.
public abstract class ScriptedGameHost : IGameHost
- Inheritance
-
objectScriptedGameHost
- Implements
- Derived
Properties
Kind
public abstract GameHostKind Kind { get; }
Property Value
Name
public string Name { get; }
Property Value
- string
Shell
public HostShell Shell { get; }
Property Value
Methods
AcquireLockAsync(string, string, TimeSpan, CancellationToken)
Takes an advisory lock at lockPath, a directory on the host, for owner (a run id).
The claim is the exclusive creation of an owner file inside it (O_EXCL, or CreateNew on Windows), which exactly one claimer
can win; the directory itself may already exist. Each acquisition claims as owner plus a unique id
(Owner), so two runs that pass the same owner never both hold the lock, and only this handle can
release it. Another claimant's lock, or an unproven claim, throws HostLockException; nothing is waited for or
retried. An unproven claim's message names the claimant it tried: check the lock with it before deciding what to do.
A lock left by a crashed run stays until a person removes it.
public Task<HostLock> AcquireLockAsync(string lockPath, string owner, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
lockPathstringownerstringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<HostLock>
CheckLockAsync(string, string, TimeSpan, CancellationToken)
Reads the lock: Free, Yours or HeldByOther. Changes nothing.
public Task<HostLockResult> CheckLockAsync(string lockPath, string owner, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
lockPathstringownerstringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<HostLockResult>
FetchDirectoryAsync(string, string, TimeSpan, CancellationToken)
Copies hostDirectory into localDirectory, which must not exist yet: the host packs it with
tar (no macOS AppleDouble files), the archive's SHA-256 and size are checked on both ends, and it is extracted here (entries
that would land outside it are refused). A local directory this call created is removed again if anything fails.
public Task<FetchedDirectory> FetchDirectoryAsync(string hostDirectory, string localDirectory, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
hostDirectorystringlocalDirectorystringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<FetchedDirectory>
LogOffsetAsync(string, TimeSpan, CancellationToken)
The log's current length in bytes (0 if it does not exist), for a later WaitForLogAsync(string, long, Regex, IReadOnlyList<Regex>?, TimeSpan, CancellationToken).
public Task<long> LogOffsetAsync(string logPath, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
logPathstringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<long>
OpenCliTunnelAsync(int, TimeSpan, int, CancellationToken)
A local loopback endpoint for the ValheimCLI listening on the host's 127.0.0.1:hostPort.
public abstract Task<CliTunnel> OpenCliTunnelAsync(int hostPort, TimeSpan readyTimeout, int localPort = 0, CancellationToken cancellation = default)
Parameters
hostPortintreadyTimeoutTimeSpanlocalPortintcancellationCancellationToken
Returns
- Task<CliTunnel>
ReleaseLockAsync(string, string, TimeSpan, CancellationToken)
Removes the lock only if it names exactly owner; another owner's lock is left alone.
public Task<HostLockResult> ReleaseLockAsync(string lockPath, string owner, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
lockPathstringownerstringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<HostLockResult>
RunAsync(string, IReadOnlyDictionary<string, string>?, TimeSpan, CancellationToken)
Runs script on the host. Each variable arrives as a literal assignment before the script, never parsed by
any shell: bash name='value', PowerShell $name = 'value'. A PowerShell script runs with
$ErrorActionPreference = 'Stop', from its own temporary .ps1 file, and ends with its exit N, 0 when it falls off
its end, or 1 for an uncaught error. A bash script's CRLF line endings become LF; its exit status is bash's. Its standard
input is empty. The working directory is the ssh user's home, the container's working directory, or this process's.
A Windows host without PowerShell 7 ends as TransportFailed, its error naming the install command.
public Task<HostResult> RunAsync(string script, IReadOnlyDictionary<string, string>? variables, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
scriptstringvariablesIReadOnlyDictionary<string, string>timeoutTimeSpancancellationCancellationToken
Returns
- Task<HostResult>
ShipFilesAsync(string, string, TimeSpan, CancellationToken)
Ships the files under localDirectory (as a tar archive, checked by SHA-256 on the host) into
hostDirectory, which must not exist yet. SOURCE.txt there records the hash.
public Task<Shipment> ShipFilesAsync(string localDirectory, string hostDirectory, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
localDirectorystringhostDirectorystringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<Shipment>
ShipRevisionAsync(string, string, string, TimeSpan, CancellationToken)
Ships one committed revision: git archive of revision (tracked files only, never the working tree)
is sent to the host, its SHA-256 checked there, and extracted into hostDirectory, which must not exist yet.
SOURCE.txt there records the commit, tree and hash. A directory this call created is removed again if extraction fails.
public Task<Shipment> ShipRevisionAsync(string repository, string revision, string hostDirectory, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
repositorystringrevisionstringhostDirectorystringtimeoutTimeSpancancellationCancellationToken
Returns
- Task<Shipment>
WaitForLogAsync(string, long, Regex, IReadOnlyList<Regex>?, TimeSpan, CancellationToken)
Follows logPath on the host from byte fromOffset, event driven there (tail -F,
or a file watcher under PowerShell), and matches each complete line here with .NET regular expressions, so a pattern means
the same on every host. A line matching one of failures (checked first) ends the wait as
FailureMatched. The log may not exist yet. Take the offset with LogOffsetAsync(string, TimeSpan, CancellationToken)
before the action whose line you await; a log the game recreates for each boot is best given a fresh path (a disposable
runtime) and offset 0, because a replacement longer than the offset cannot be told apart. The host stops following on its
own a little after the deadline. A transport failure or a follower that ends early throws HostOperationException.
public Task<HostLogResult> WaitForLogAsync(string logPath, long fromOffset, Regex success, IReadOnlyList<Regex>? failures, TimeSpan timeout, CancellationToken cancellation = default)
Parameters
logPathstringfromOffsetlongsuccessRegexfailuresIReadOnlyList<Regex>timeoutTimeSpancancellationCancellationToken
Returns
- Task<HostLogResult>