469 lines
20 KiB
Go
469 lines
20 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadSelectsLocalComposeFilesForAnInstallationInPathsWithSpaces(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
installationPath, projectDirectory, envFile, override := writeInstallation(t, "local")
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatalf("Load() error = %v", err)
|
|
}
|
|
|
|
if installation.ProjectDirectory != projectDirectory {
|
|
t.Errorf("ProjectDirectory = %q, want %q", installation.ProjectDirectory, projectDirectory)
|
|
}
|
|
if installation.EnvFile != envFile {
|
|
t.Errorf("EnvFile = %q, want %q", installation.EnvFile, envFile)
|
|
}
|
|
if !strings.Contains(installationPath, "installation folder with spaces") {
|
|
t.Fatalf("test setup must exercise a path with spaces: %q", installationPath)
|
|
}
|
|
|
|
want := []string{
|
|
filepath.Join(projectDirectory, "compose.yaml"),
|
|
filepath.Join(projectDirectory, "deploy", "compose.local.yaml"),
|
|
override,
|
|
}
|
|
assertStringsEqual(t, installation.ComposeFiles(), want)
|
|
}
|
|
|
|
func TestLoadSelectsServerComposeFiles(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
installationPath, projectDirectory, _, override := writeInstallation(t, "server")
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatalf("Load() error = %v", err)
|
|
}
|
|
|
|
want := []string{
|
|
filepath.Join(projectDirectory, "compose.yaml"),
|
|
filepath.Join(projectDirectory, "deploy", "compose.server.yaml"),
|
|
override,
|
|
}
|
|
assertStringsEqual(t, installation.ComposeFiles(), want)
|
|
}
|
|
|
|
func TestLoadAcceptsServerRuntimeProjectionAndPlacesAutomaticOverrideBeforeCurrentImage(t *testing.T) {
|
|
installationPath, projectDirectory, envFile, override := writeInstallation(t, "server")
|
|
root := filepath.Dir(installationPath)
|
|
authDirectory := filepath.Join(root, "canonical-auth")
|
|
runtimeDirectory := filepath.Join(root, "runtime-auth")
|
|
automaticOverride := filepath.Join(projectDirectory, "deploy", "compose.auth-runtime-projection.yaml")
|
|
if err := os.WriteFile(automaticOverride, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
candidate := Installation{Path: installationPath, ProjectDirectory: projectDirectory}
|
|
currentImage := candidate.CurrentImageOverridePath()
|
|
if err := os.MkdirAll(filepath.Dir(currentImage), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(currentImage, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
writeRuntimeProjectionFixture(t, installationPath, envFile, "server", authDirectory, runtimeDirectory, runtimeDirectory, 10001, 10001, []string{override})
|
|
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatalf("Load() error = %v", err)
|
|
}
|
|
if !installation.HasRuntimeAuthProjection() {
|
|
t.Fatal("HasRuntimeAuthProjection() = false, want true")
|
|
}
|
|
projection := installation.RuntimeAuthProjection()
|
|
if projection == nil || projection.Directory != runtimeDirectory || projection.UID != 10001 || projection.GID != 10001 {
|
|
t.Fatalf("RuntimeAuthProjection() = %#v", projection)
|
|
}
|
|
projection.Directory = "mutated"
|
|
if got := installation.RuntimeAuthProjection(); got == nil || got.Directory != runtimeDirectory {
|
|
t.Fatalf("RuntimeAuthProjection() did not return an independent copy: %#v", got)
|
|
}
|
|
|
|
want := []string{
|
|
filepath.Join(projectDirectory, "compose.yaml"),
|
|
filepath.Join(projectDirectory, "deploy", "compose.server.yaml"),
|
|
override,
|
|
automaticOverride,
|
|
currentImage,
|
|
}
|
|
assertStringsEqual(t, installation.ComposeFiles(), want)
|
|
}
|
|
|
|
func TestLoadRejectsInvalidRuntimeProjection(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
profile string
|
|
configDirectory func(root string) string
|
|
runtimeDirectory func(root string) string
|
|
environmentRoot func(root string) string
|
|
uid, gid uint32
|
|
manualOverride bool
|
|
}{
|
|
{name: "local profile", profile: "local", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "runtime-auth") }, uid: 10001, gid: 10001},
|
|
{name: "relative runtime directory", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(string) string { return "relative-runtime-auth" }, environmentRoot: func(string) string { return "relative-runtime-auth" }, uid: 10001, gid: 10001},
|
|
{name: "noncanonical runtime directory", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return root + "/runtime-auth/../runtime-auth" }, environmentRoot: func(root string) string { return filepath.Join(root, "runtime-auth") }, uid: 10001, gid: 10001},
|
|
{name: "equal canonical and runtime directories", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "canonical-auth") }, uid: 10001, gid: 10001},
|
|
{name: "uid mismatch", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "runtime-auth") }, uid: 10000, gid: 10001},
|
|
{name: "gid mismatch", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "runtime-auth") }, uid: 10001, gid: 10000},
|
|
{name: "missing runtime environment", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return "" }, uid: 10001, gid: 10001},
|
|
{name: "mismatched runtime environment", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "different-runtime-auth") }, uid: 10001, gid: 10001},
|
|
{name: "manual automatic override", profile: "server", configDirectory: func(root string) string { return filepath.Join(root, "canonical-auth") }, runtimeDirectory: func(root string) string { return filepath.Join(root, "runtime-auth") }, environmentRoot: func(root string) string { return filepath.Join(root, "runtime-auth") }, uid: 10001, gid: 10001, manualOverride: true},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
installationPath, projectDirectory, envFile, override := writeInstallation(t, test.profile)
|
|
root := filepath.Dir(installationPath)
|
|
automaticOverride := filepath.Join(projectDirectory, "deploy", "compose.auth-runtime-projection.yaml")
|
|
if err := os.WriteFile(automaticOverride, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
overrides := []string{override}
|
|
if test.manualOverride {
|
|
overrides = append(overrides, automaticOverride)
|
|
}
|
|
writeRuntimeProjectionFixture(t, installationPath, envFile, test.profile, test.configDirectory(root), test.runtimeDirectory(root), test.environmentRoot(root), test.uid, test.gid, overrides)
|
|
|
|
if _, err := Load(installationPath); err == nil {
|
|
t.Fatal("Load() unexpectedly accepted an invalid runtime authentication projection")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsRuntimeProjectionEnvironmentWithoutDescriptor(t *testing.T) {
|
|
installationPath, _, envFile, _ := writeInstallation(t, "server")
|
|
authDirectory := filepath.Join(filepath.Dir(installationPath), "auth")
|
|
runtimeDirectory := filepath.Join(filepath.Dir(installationPath), "runtime-auth")
|
|
contents := "THT_AUTH_CONFIG_ROOT=" + strconv.Quote(authDirectory) + "\nTHT_AUTH_RUNTIME_ROOT=" + strconv.Quote(runtimeDirectory) + "\n"
|
|
if err := os.WriteFile(envFile, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := Load(installationPath); err == nil {
|
|
t.Fatal("Load() unexpectedly accepted THT_AUTH_RUNTIME_ROOT without runtimeProjection")
|
|
}
|
|
}
|
|
|
|
func TestLoadRequiresAndReturnsTypedWorkspaceRepositoryForGitInstallations(t *testing.T) {
|
|
installationPath, projectDirectory, envFile, _ := writeInstallation(t, "local")
|
|
gitOverride := filepath.Join(projectDirectory, "deploy", "compose.git-ssh.yaml")
|
|
if err := os.WriteFile(gitOverride, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
secretRoot := filepath.Dir(envFile)
|
|
privateKey := filepath.Join(secretRoot, "git-key")
|
|
knownHosts := filepath.Join(secretRoot, "known-hosts")
|
|
for _, file := range []string{privateKey, knownHosts} {
|
|
if err := os.WriteFile(file, []byte("fixture\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
remote := "git@gitea.example.org:clinical/workspaces.git"
|
|
environment := strings.Join([]string{
|
|
"THT_AUTH_CONFIG_ROOT=" + strconv.Quote(filepath.Join(filepath.Dir(envFile), "auth")),
|
|
"THT_WORKSPACE_GIT_REMOTE=" + remote,
|
|
"THT_WORKSPACE_GIT_BRANCH=main",
|
|
"THT_WORKSPACE_GIT_SSH_KEY_FILE=" + privateKey,
|
|
"THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=" + knownHosts,
|
|
}, "\n") + "\n"
|
|
if err := os.WriteFile(envFile, []byte(environment), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
contents := "profile: local\nprojectDirectory: " + projectDirectory +
|
|
"\nenvFile: " + envFile +
|
|
"\nauthentication:\n configDirectory: " + filepath.Join(filepath.Dir(envFile), "auth") +
|
|
"\nworkspaceRepository:\n remote: " + remote +
|
|
"\n branch: main\n access: ssh\noverrides:\n - " + gitOverride + "\n"
|
|
if err := os.WriteFile(installationPath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if installation.WorkspaceRepository.Remote != remote ||
|
|
installation.WorkspaceRepository.Branch != "main" ||
|
|
installation.WorkspaceRepository.Access != "ssh" {
|
|
t.Fatalf("WorkspaceRepository = %#v", installation.WorkspaceRepository)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsGitOverrideWithoutTypedWorkspaceRepository(t *testing.T) {
|
|
installationPath, projectDirectory, envFile, _ := writeInstallation(t, "local")
|
|
gitOverride := filepath.Join(projectDirectory, "deploy", "compose.git-https.yaml")
|
|
if err := os.WriteFile(gitOverride, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
contents := "profile: local\nprojectDirectory: " + projectDirectory +
|
|
"\nenvFile: " + envFile + "\noverrides:\n - " + gitOverride + "\n"
|
|
contents = strings.Replace(contents, "\noverrides:", "\nauthentication:\n configDirectory: "+filepath.Join(filepath.Dir(envFile), "auth")+"\noverrides:", 1)
|
|
if err := os.WriteFile(installationPath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := Load(installationPath)
|
|
if err == nil || !strings.Contains(err.Error(), "workspaceRepository") {
|
|
t.Fatalf("Load() error = %v, want workspaceRepository error", err)
|
|
}
|
|
}
|
|
|
|
func TestComposeArgsAutomaticallyIncludeTheInstallationCurrentImageOverride(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
installationPath, _, _, _ := writeInstallation(t, "local")
|
|
seed, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
currentImage := seed.CurrentImageOverridePath()
|
|
if err := os.MkdirAll(filepath.Dir(currentImage), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(currentImage, []byte("services:\n core:\n image: candidate\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
args := installation.ComposeArgs("up", "--detach")
|
|
want := []string{"-f", currentImage, "up", "--detach"}
|
|
if !containsSequence(args, want) {
|
|
t.Fatalf("ComposeArgs() = %#v, want durable override immediately before command", args)
|
|
}
|
|
}
|
|
|
|
func TestComposeArgsWithFinalOverridePreservesCurrentImagePrecedence(t *testing.T) {
|
|
installationPath, _, _, _ := writeInstallation(t, "server")
|
|
seed, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.MkdirAll(seed.ControlDirectory(), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(seed.CurrentImageOverridePath(), []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
final := filepath.Join(seed.ControlDirectory(), "migration.yaml")
|
|
if err := os.WriteFile(final, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
args, err := installation.ComposeArgsWithFinalOverride(final, "--profile", "session-migrate", "config")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []string{"-f", installation.CurrentImageOverridePath(), "-f", final, "--profile", "session-migrate", "config"}
|
|
if !containsSequence(args, want) {
|
|
t.Fatalf("ComposeArgsWithFinalOverride() = %#v, want %#v", args, want)
|
|
}
|
|
}
|
|
|
|
func TestPreservationPathsReturnsCanonicalBindRootsBackupsAndSecretFiles(t *testing.T) {
|
|
installationPath, _, envFile, _ := writeInstallation(t, "server")
|
|
root := filepath.Dir(envFile)
|
|
var wanted []string
|
|
var lines []string
|
|
for _, item := range []struct{ key, name string }{
|
|
{"THT_DATA_ROOT", "data"},
|
|
{"THT_PI_STATE_ROOT", "pi-state"},
|
|
{"THT_WORKSPACE_REGISTRY_ROOT", "workspace-registry"},
|
|
{"THT_BACKUP_ROOT", "backups"},
|
|
} {
|
|
path := filepath.Join(root, item.name)
|
|
if err := os.Mkdir(path, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wanted = append(wanted, path)
|
|
lines = append(lines, item.key+"="+path)
|
|
}
|
|
secret := filepath.Join(root, "secret")
|
|
if err := os.WriteFile(secret, []byte("secret"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wanted = append(wanted, secret)
|
|
lines = append(lines, "APP_TOKEN_FILE="+secret)
|
|
lines = append(lines, "THT_AUTH_CONFIG_ROOT="+strconv.Quote(filepath.Join(root, "auth")))
|
|
if err := os.WriteFile(envFile, []byte(strings.Join(lines, "\n")+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := installation.PreservationPaths()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertStringsEqual(t, got, wanted)
|
|
}
|
|
|
|
func TestInstallationControlPathsAreIsolatedForDescriptorsSharingOneCheckout(t *testing.T) {
|
|
projectDirectory := t.TempDir()
|
|
first := Installation{Path: filepath.Join(t.TempDir(), installationFileName), ProjectDirectory: projectDirectory}
|
|
second := Installation{Path: filepath.Join(t.TempDir(), installationFileName), ProjectDirectory: projectDirectory}
|
|
|
|
if first.CurrentImageOverridePath() == second.CurrentImageOverridePath() {
|
|
t.Fatalf("shared-checkout installations reused %q", first.CurrentImageOverridePath())
|
|
}
|
|
for _, installation := range []Installation{first, second} {
|
|
if filepath.Dir(filepath.Dir(installation.CurrentImageOverridePath())) != filepath.Join(projectDirectory, ".tht") {
|
|
t.Fatalf("current-image path %q is not installation-specific under .tht", installation.CurrentImageOverridePath())
|
|
}
|
|
if filepath.Dir(installation.UpdateStatePath()) != filepath.Dir(installation.CurrentImageOverridePath()) {
|
|
t.Fatalf("state %q and selector %q do not share one installation control directory", installation.UpdateStatePath(), installation.CurrentImageOverridePath())
|
|
}
|
|
if got, want := installation.RestartStatePath(), filepath.Join(installation.ControlDirectory(), "restart-state.json"); got != want {
|
|
t.Fatalf("RestartStatePath() = %q, want %q", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsRelativeInstallationPaths(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := Load("thothii-installation.yaml")
|
|
if err == nil || !strings.Contains(err.Error(), "absolute") {
|
|
t.Fatalf("Load() error = %v, want an absolute-path error", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadRequiresCanonicalAuthenticationDirectoryMatchingEnvironment(t *testing.T) {
|
|
installationPath, _, envFile, _ := writeInstallation(t, "local")
|
|
authDirectory := filepath.Join(filepath.Dir(installationPath), "auth")
|
|
contents, err := os.ReadFile(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(envFile, []byte("THT_AUTH_CONFIG_ROOT="+strconv.Quote(authDirectory)+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
installation, err := Load(installationPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := installation.AuthenticationDirectory(); got != authDirectory {
|
|
t.Fatalf("AuthenticationDirectory() = %q, want %q", got, authDirectory)
|
|
}
|
|
|
|
for _, invalid := range []string{"relative/auth", authDirectory + "/../auth"} {
|
|
bad := strings.Replace(string(contents), authDirectory, invalid, 1)
|
|
if err := os.WriteFile(installationPath, []byte(bad), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := Load(installationPath); err == nil {
|
|
t.Fatalf("Load accepted unsafe auth directory %q", invalid)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseAuthenticationDirectoryEnvironment(t *testing.T) {
|
|
values, err := parseComposeDotenv([]byte("THT_AUTH_CONFIG_ROOT=\"/tmp/auth\"\n"))
|
|
if err != nil || values["THT_AUTH_CONFIG_ROOT"] != "/tmp/auth" {
|
|
t.Fatalf("values=%#v err=%v", values, err)
|
|
}
|
|
}
|
|
|
|
func writeRuntimeProjectionFixture(t *testing.T, installationPath, envFile, profile, configDirectory, runtimeDirectory, environmentRoot string, uid, gid uint32, overrides []string) {
|
|
t.Helper()
|
|
lines := []string{"THT_AUTH_CONFIG_ROOT=" + strconv.Quote(configDirectory)}
|
|
if environmentRoot != "" {
|
|
lines = append(lines, "THT_AUTH_RUNTIME_ROOT="+strconv.Quote(environmentRoot))
|
|
}
|
|
if err := os.WriteFile(envFile, []byte(strings.Join(lines, "\n")+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
projectDirectory := filepath.Join(filepath.Dir(installationPath), "project directory with spaces")
|
|
contents := "profile: " + profile + "\nprojectDirectory: " + projectDirectory + "\nenvFile: " + envFile + "\nauthentication:\n configDirectory: " + configDirectory + "\n runtimeProjection:\n directory: " + runtimeDirectory + "\n uid: " + strconv.FormatUint(uint64(uid), 10) + "\n gid: " + strconv.FormatUint(uint64(gid), 10) + "\noverrides:\n"
|
|
for _, override := range overrides {
|
|
contents += " - " + override + "\n"
|
|
}
|
|
if err := os.WriteFile(installationPath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func writeInstallation(t *testing.T, profile string) (string, string, string, string) {
|
|
t.Helper()
|
|
|
|
temporaryRoot, err := filepath.EvalSymlinks(os.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
physicalRoot, err := os.MkdirTemp(temporaryRoot, "tht-config-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = os.RemoveAll(physicalRoot) })
|
|
root := filepath.Join(physicalRoot, "installation folder with spaces")
|
|
projectDirectory := filepath.Join(root, "project directory with spaces")
|
|
if err := os.MkdirAll(filepath.Join(projectDirectory, "deploy"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, name := range []string{"compose.yaml", filepath.Join("deploy", "compose.local.yaml"), filepath.Join("deploy", "compose.server.yaml")} {
|
|
if err := os.WriteFile(filepath.Join(projectDirectory, name), []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
envFile := filepath.Join(root, "environment file.env")
|
|
authDirectory := filepath.Join(root, "auth")
|
|
if err := os.WriteFile(envFile, []byte("SAFE_VALUE=1\nTHT_AUTH_CONFIG_ROOT="+strconv.Quote(authDirectory)+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
override := filepath.Join(root, "extra override.yaml")
|
|
if err := os.WriteFile(override, []byte("services: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
installationPath := filepath.Join(root, "thothii-installation.yaml")
|
|
contents := "profile: " + profile + "\nprojectDirectory: " + projectDirectory + "\nenvFile: " + envFile + "\nauthentication:\n configDirectory: " + authDirectory + "\noverrides:\n - " + override + "\n"
|
|
if err := os.WriteFile(installationPath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return installationPath, projectDirectory, envFile, override
|
|
}
|
|
|
|
func assertStringsEqual(t *testing.T, got, want []string) {
|
|
t.Helper()
|
|
if len(got) != len(want) {
|
|
t.Fatalf("length = %d, want %d: got %#v", len(got), len(want), got)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Errorf("value[%d] = %q, want %q", i, got[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func containsSequence(values, wanted []string) bool {
|
|
for start := range values {
|
|
if len(values)-start < len(wanted) {
|
|
continue
|
|
}
|
|
matched := true
|
|
for offset := range wanted {
|
|
if values[start+offset] != wanted[offset] {
|
|
matched = false
|
|
break
|
|
}
|
|
}
|
|
if matched {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|