package upgrade import ( "os" "path/filepath" "strings" "testing" ) // The engine placed by hand becomes a copy of the proved one when the two differ (novox/hq issue 356): the // command on PATH is the build that runs the machine. func TestTheFallbackBecomesACopyOfTheProvedEngine(t *testing.T) { dir := t.TempDir() self := filepath.Join(dir, VersionsDirName, "v2", BinaryName) if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(self, []byte("the proved engine"), 0o755); err != nil { t.Fatal(err) } fallback := filepath.Join(dir, "bin", BinaryName) if err := os.MkdirAll(filepath.Dir(fallback), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(fallback, []byte("the stale engine placed by hand"), 0o644); err != nil { t.Fatal(err) } renewed, err := RenewFallback(self, fallback) if err != nil || !renewed { t.Fatalf("renewed %v, %v", renewed, err) } got, err := os.ReadFile(fallback) if err != nil || string(got) != "the proved engine" { t.Fatalf("the fallback holds %q, %v", got, err) } info, err := os.Stat(fallback) if err != nil || info.Mode().Perm() != 0o755 { t.Fatalf("the fallback's mode is %v, %v; want 0755 so it can be run", info.Mode(), err) } if _, err := os.Stat(self); err != nil { t.Fatalf("the running engine was touched: %v", err) } // Already a copy: left alone, so a proof every start does not rewrite it every start. before, _ := os.Stat(fallback) renewed, err = RenewFallback(self, fallback) if err != nil || renewed { t.Fatalf("a fallback that is already a copy was renewed again: %v, %v", renewed, err) } after, _ := os.Stat(fallback) if !os.SameFile(before, after) { t.Fatal("a fallback that is already a copy was replaced") } if left, _ := filepath.Glob(filepath.Join(filepath.Dir(fallback), "."+BinaryName+"-*")); len(left) > 0 { t.Fatalf("temporary files left beside the fallback: %v", left) } } // An engine running from the fallback itself — nothing delivered yet — renews nothing: it would copy a file // over itself. func TestAnEngineRunningFromTheFallbackRenewsNothing(t *testing.T) { dir := t.TempDir() fallback := filepath.Join(dir, BinaryName) if err := os.WriteFile(fallback, []byte("placed by hand and running"), 0o755); err != nil { t.Fatal(err) } renewed, err := RenewFallback(fallback, fallback) if err != nil || renewed { t.Fatalf("renewed %v, %v", renewed, err) } } // Nothing placed by hand: the proved engine is placed, so the launcher has a fallback and the machine a command. func TestAMissingFallbackIsPlaced(t *testing.T) { dir := t.TempDir() self := filepath.Join(dir, "v1", BinaryName) if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil { t.Fatal(err) } fallback := filepath.Join(dir, BinaryName) renewed, err := RenewFallback(self, fallback) if err != nil || !renewed { t.Fatalf("renewed %v, %v", renewed, err) } if got, _ := os.ReadFile(fallback); string(got) != "proved" { t.Fatalf("placed %q", got) } } // A link at the fallback's path is refused and left as it is: the mesh creates no link and writes through none // (novox/hq ADR 0012). The link's target is untouched too. func TestALinkAtTheFallbackIsRefusedAndLeft(t *testing.T) { dir := t.TempDir() self := filepath.Join(dir, "v1", BinaryName) if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil { t.Fatal(err) } target := filepath.Join(dir, "somebody-elses") if err := os.WriteFile(target, []byte("theirs"), 0o755); err != nil { t.Fatal(err) } fallback := filepath.Join(dir, BinaryName) if err := os.Symlink(target, fallback); err != nil { t.Fatal(err) } renewed, err := RenewFallback(self, fallback) if err == nil || renewed || !strings.Contains(err.Error(), "link") { t.Fatalf("a link was taken: %v, %v", renewed, err) } if got, _ := os.ReadFile(target); string(got) != "theirs" { t.Fatalf("the link's target was written: %q", got) } if info, err := os.Lstat(fallback); err != nil || info.Mode()&os.ModeSymlink == 0 { t.Fatalf("the link was replaced: %v %v", info, err) } } // A running engine that cannot be read is said, not copied as nothing. func TestAnUnreadableRunningEngineIsSaid(t *testing.T) { dir := t.TempDir() fallback := filepath.Join(dir, BinaryName) if err := os.WriteFile(fallback, []byte("placed"), 0o755); err != nil { t.Fatal(err) } renewed, err := RenewFallback(filepath.Join(dir, "gone"), fallback) if err == nil || renewed { t.Fatalf("renewed %v, %v", renewed, err) } if got, _ := os.ReadFile(fallback); string(got) != "placed" { t.Fatalf("the fallback was written from nothing: %q", got) } if _, err := RenewFallback("", fallback); err == nil { t.Fatal("an empty path was taken") } } // The fallback's path is the launcher's: its environment variable, or the default. func TestTheFallbackPathIsTheLaunchers(t *testing.T) { t.Setenv(FallbackVar, "") if FallbackPath() != DefaultFallback { t.Fatalf("the default is %q", FallbackPath()) } t.Setenv(FallbackVar, "/elsewhere/nox-mesh-host") if FallbackPath() != "/elsewhere/nox-mesh-host" { t.Fatalf("the override is %q", FallbackPath()) } } // A fallback that is not a regular file — a directory where the engine should be — is refused and left: the mesh // replaces a file, never something else at its name. func TestAFallbackThatIsNotARegularFileIsRefused(t *testing.T) { dir := t.TempDir() self := filepath.Join(dir, "v1", BinaryName) if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil { t.Fatal(err) } fallback := filepath.Join(dir, BinaryName) if err := os.Mkdir(fallback, 0o755); err != nil { t.Fatal(err) } renewed, err := RenewFallback(self, fallback) if err == nil || renewed || !strings.Contains(err.Error(), "not a regular file") { t.Fatalf("a directory at the fallback was taken: %v, %v", renewed, err) } if info, err := os.Lstat(fallback); err != nil || !info.IsDir() { t.Fatalf("the directory was replaced: %v %v", info, err) } // And a running engine that is not a regular file is refused before anything is written. if _, err := RenewFallback(dir, filepath.Join(dir, "elsewhere")); err == nil || !strings.Contains(err.Error(), "not a regular file") { t.Fatalf("a directory was taken as the running engine: %v", err) } if _, err := os.Lstat(filepath.Join(dir, "elsewhere")); err == nil { t.Fatal("something was placed from a directory") } }