#load "bootstrap.fsx" open System open System.IO open System.Runtime.InteropServices open System.Security.Cryptography open System.Text open Bootstrap let check condition message = if not condition then failwith message let root = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")) let paths = { Data = root + "/data"; State = root + "/state"; Backups = root + "/backups"; Files = root + "/files" } let salt = Encoding.UTF8.GetBytes "delivered saltatory" let saltHash = SHA256.HashData salt |> Convert.ToHexString |> _.ToLowerInvariant() let config = { Paths = paths; PasswordPath = root + "/password"; Eula = "TRUE"; Args = "libraries/loader/unix_args.txt"; Saltatory = saltHash } let mutable downloads = 0 let data = System.Collections.Generic.Dictionary() let put key (value: string) = data[key] <- Encoding.UTF8.GetBytes value let hash (value: byte[]) = SHA256.HashData value |> Convert.ToHexString |> _.ToLowerInvariant() let manifests = [ "mods", "mods.sha256"; "config", "config.sha256"; "defaultconfigs", "defaultconfigs.sha256" "kubejs", "kubejs.sha256"; "libraries", "libraries.sha256"; "libraries-integratedscripting", "libraries-integratedscripting.sha256" "settings", "settings.sha256"; "tools", "tools.sha256" "world/datapacks", "world-datapacks.sha256"; "world/serverconfig", "world-serverconfig.sha256" ] |> Map.ofList let manifest name = let prefix = manifests |> Map.toSeq |> Seq.find (fun (_, inventory) -> inventory = name) |> fst data |> Seq.filter (fun item -> item.Key.StartsWith(prefix + "/")) |> Seq.map (fun item -> hash item.Value + " " + item.Key.Substring(prefix.Length + 1)) |> String.concat "\n" let fetch key expected path = if not (File.Exists path) || digest path <> expected then downloads <- downloads + 1 File.WriteAllBytes(path, data[key]) check (digest path = expected) "fixture hash" let fetchSaltatory expected path = if not (File.Exists path) || digest path <> expected then downloads <- downloads + 1 File.WriteAllBytes(path, salt) check (digest path = expected) "saltatory hash" let load () = run config Architecture.X64 manifest fetch fetchSaltatory try Directory.CreateDirectory paths.Files |> ignore text (paths.Files + "/server.properties") "level-seed=123" text config.PasswordPath "synthetic-password" put "mods/old.jar" "old" put "mods/saltatory-0.42.1.jar" "pack saltatory" put "config/sample.toml" "config" put "config/chunky/tasks/minecraft/overworld.properties" "artifact task state" put "libraries/loader/unix_args.txt" "loader args" put "settings/user_jvm_args.txt" "-Xmx1G" put "tools/amd64/mc-server-runner" "runner" put "tools/amd64/mc-monitor" "monitor" put "world/serverconfig/ftbranks/ranks.snbt" "ranks" load () let first = downloads check (first = 8) "initial downloads" check (not (File.Exists(paths.Data + "/config/chunky/tasks/minecraft/overworld.properties"))) "artifact task state copied" check (Directory.Exists(paths.State + "/world/data/chunky")) "mutable task directory missing" check (digest (paths.Data + "/mods/saltatory.jar") = saltHash) "delivered saltatory missing" check (not (File.Exists(paths.Data + "/mods/saltatory-0.42.1.jar"))) "pack saltatory retained" check (File.ReadAllText(paths.Data + "/server.properties") = "level-seed=123\nrcon.password=synthetic-password\n") "properties" check (File.ReadAllText(paths.Data + "/server_args.txt") = "loader args") "loader args" text (paths.State + "/ops.json") "operators" text (paths.State + "/banned-players.json") "banned" text (paths.State + "/world/serverconfig/ftbranks/players.snbt") "players" text (paths.State + "/world/data/chunky/checkpoint") "task progress" Directory.Delete(paths.Data, true) load () check (downloads = first) "cached files re-downloaded" check (File.ReadAllText(paths.State + "/ops.json") = "operators") "operators changed" check (File.ReadAllText(paths.State + "/banned-players.json") = "banned") "bans changed" check (File.ReadAllText(paths.State + "/world/serverconfig/ftbranks/players.snbt") = "players") "player state changed" check (File.ReadAllText(paths.State + "/world/data/chunky/checkpoint") = "task progress") "task progress changed" data.Remove "mods/old.jar" |> ignore put "mods/new.jar" "new" text (paths.State + "/cache/config/sample.toml") "corrupt" load () check (downloads = first + 2) "changed or corrupt files not fetched" check (not (File.Exists(paths.State + "/cache/mods/old.jar"))) "stale cache file" check (not (File.Exists(paths.Data + "/mods/old.jar"))) "stale runtime mod" check (File.ReadAllText(paths.State + "/cache/mods/new.jar") = "new") "new mod missing" printfn "bootstrap tests passed" finally if Directory.Exists root then Directory.Delete(root, true)