108 lines
4.1 KiB
Go
108 lines
4.1 KiB
Go
package config
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// A deployment declares no format by default, and then it builds no exports at all: the door is
|
|
// unmounted and `export_formats` is empty. The default matters because the alternative — announcing
|
|
// a format because the engine that shipped with this build happened to know it — is a promise a
|
|
// client discovers is empty on a user's first download.
|
|
func TestADeploymentBuildsNoExportsUntilItSaysWhichFormats(t *testing.T) {
|
|
t.Setenv("TM_PLATFORM_STATE_DIR", "/var/lib/tmplatform")
|
|
t.Setenv("TM_PLATFORM_ENGINE_BIN", "/opt/tm/v1/tmctl")
|
|
c, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(c.Export.Formats) != 0 || c.ExportsEnabled() {
|
|
t.Fatalf("a deployment that declared nothing builds %v", c.Export.Formats)
|
|
}
|
|
t.Setenv("TM_PLATFORM_EXPORT_FORMATS", " epub , txt ")
|
|
c, err = Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(c.Export.Formats) != 2 || c.Export.Formats[0] != "epub" || c.Export.Formats[1] != "txt" {
|
|
t.Fatalf("formats %q: the declaration is a comma-separated list and its order is the one "+
|
|
"`GET /capabilities` announces", c.Export.Formats)
|
|
}
|
|
if !c.ExportsEnabled() {
|
|
t.Error("a deployment with formats, an engine and a directory still builds nothing")
|
|
}
|
|
// The directory falls out of the state directory: artifacts are platform state of exactly that
|
|
// kind, and an operator who already said where state lives should not have to say it twice.
|
|
if want := filepath.Join("/var/lib/tmplatform", "exports"); c.Export.Dir != want {
|
|
t.Errorf("exports dir %q, want %q", c.Export.Dir, want)
|
|
}
|
|
if c.Export.TTL != 24*time.Hour {
|
|
t.Errorf("TTL %s, want a day", c.Export.TTL)
|
|
}
|
|
}
|
|
|
|
// An instance with formats but NO ENGINE builds nothing: `build` is an engine call like every other,
|
|
// and a read replica that announced `epub` would answer a download with a failure every time.
|
|
func TestAReadReplicaAnnouncesNoFormatsEvenIfTheOperatorDeclaredSome(t *testing.T) {
|
|
t.Setenv("TM_PLATFORM_EXPORT_FORMATS", "epub")
|
|
c, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.ExportsEnabled() {
|
|
t.Error("an instance with no engine binary claims it can build exports")
|
|
}
|
|
}
|
|
|
|
// The three refusals that belong at BOOT, where an operator sees them, rather than at the first
|
|
// download, where they are one user's mysterious failure.
|
|
//
|
|
// ⚠ The relative directory is the sharpest of the three: the path is handed to the ENGINE as
|
|
// `--out`, and the engine runs with the BOOK's directory as its working directory — so a relative
|
|
// value would write every artifact inside somebody's book project, the one tree this platform must
|
|
// not write into (D39.110).
|
|
func TestTheExportSettingsFailAtLoadAndNotAtTheFirstDownload(t *testing.T) {
|
|
for name, env := range map[string]map[string]string{
|
|
"a format that would name a path": {"TM_PLATFORM_EXPORT_FORMATS": "../etc"},
|
|
"a format declared twice": {"TM_PLATFORM_EXPORT_FORMATS": "epub,epub"},
|
|
"a relative artifact directory": {"TM_PLATFORM_EXPORTS_DIR": "var/exports"},
|
|
"a link that expires at once": {"TM_PLATFORM_EXPORT_TTL": "0s"},
|
|
"a malformed lifetime": {"TM_PLATFORM_EXPORT_TTL": "a while"},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
for k, v := range env {
|
|
t.Setenv(k, v)
|
|
}
|
|
if _, err := Load(); err == nil {
|
|
t.Errorf("%v was accepted", env)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Every setting of this service is printed at boot with where it came from (PD-114), and a new one
|
|
// that is not is a variable an operator hunts for and cannot find.
|
|
func TestTheExportSettingsArePrintedWithTheirSource(t *testing.T) {
|
|
t.Setenv("TM_PLATFORM_EXPORT_FORMATS", "epub")
|
|
t.Setenv("TM_PLATFORM_EXPORTS_DIR", "/srv/exports")
|
|
c, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
printed := map[string]string{}
|
|
for _, s := range c.Settings {
|
|
printed[s.Key] = s.Source
|
|
}
|
|
for key, want := range map[string]string{
|
|
"TM_PLATFORM_EXPORT_FORMATS": "environment",
|
|
"TM_PLATFORM_EXPORTS_DIR": "environment",
|
|
"TM_PLATFORM_EXPORT_TTL": "default",
|
|
} {
|
|
if got, ok := printed[key]; !ok {
|
|
t.Errorf("%s is not printed at boot", key)
|
|
} else if got != want {
|
|
t.Errorf("%s came from %q, want %q", key, got, want)
|
|
}
|
|
}
|
|
}
|