Files
DDI/agent/role/internal/fsutil/fsutil_test.go
T
sir_melonchenandClaude Opus 5.5 70643f8146 feat(agent/dns): keys file, secondary zones and their health
The DNS role installs ddi-suite-keys.conf (a keys file without keys for
revisions from before M5, so that named.conf can always include it),
includes it before ddi-suite.conf in the validation named.conf, accepts
secondary zone files in <zone_dir>/secondary/ and creates that
directory with the mode and owner of zone_dir without ever touching its
content. The health check queries secondary zones too; a zone still
waiting for its first transfer is reported but does not fail the
deployment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:30:40 +02:00

176 lines
4.7 KiB
Go

// SPDX-License-Identifier: Apache-2.0
package fsutil
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
func TestWriteFileReplacesAtomically(t *testing.T) {
dir := t.TempDir()
p := filepath.Join(dir, "f.conf")
if err := os.WriteFile(p, []byte("old"), 0o600); err != nil {
t.Fatal(err)
}
if err := WriteFile(p, []byte("new"), 0o640, OwnerFor(p)); err != nil {
t.Fatal(err)
}
got, err := os.ReadFile(p)
if err != nil || string(got) != "new" {
t.Fatalf("content = %q, %v", got, err)
}
if runtime.GOOS != "windows" {
fi, _ := os.Stat(p)
if fi.Mode().Perm() != 0o640 {
t.Errorf("mode = %o, want 640", fi.Mode().Perm())
}
}
entries, _ := os.ReadDir(dir)
for _, e := range entries {
if strings.HasPrefix(e.Name(), tempPrefix) {
t.Errorf("temporary file left behind: %s", e.Name())
}
}
}
func TestWriteFileFailsWithoutDirectory(t *testing.T) {
if err := WriteFile(filepath.Join(t.TempDir(), "missing", "f"), []byte("x"), 0o640, Owner{}); err == nil {
t.Fatal("expected an error")
}
}
func TestBackupRestore(t *testing.T) {
dir := t.TempDir()
existing := filepath.Join(dir, "existing")
created := filepath.Join(dir, "created")
removed := filepath.Join(dir, "removed")
for _, p := range []string{existing, removed} {
if err := os.WriteFile(p, []byte("orig "+filepath.Base(p)), 0o640); err != nil {
t.Fatal(err)
}
}
var b Backup
for _, p := range []string{existing, created, removed, existing} {
if err := b.Save(p); err != nil {
t.Fatal(err)
}
}
if got := len(b.Paths()); got != 3 {
t.Fatalf("saved %d paths, want 3 (duplicates ignored)", got)
}
// Change everything.
if err := WriteFile(existing, []byte("changed"), 0o600, Owner{}); err != nil {
t.Fatal(err)
}
if err := WriteFile(created, []byte("new"), 0o600, Owner{}); err != nil {
t.Fatal(err)
}
if err := Remove(removed); err != nil {
t.Fatal(err)
}
if err := b.Restore(); err != nil {
t.Fatal(err)
}
for p, want := range map[string]string{existing: "orig existing", removed: "orig removed"} {
got, err := os.ReadFile(p)
if err != nil || string(got) != want {
t.Errorf("%s = %q, %v; want %q", p, got, err, want)
}
if runtime.GOOS != "windows" {
if fi, _ := os.Stat(p); fi.Mode().Perm() != 0o640 {
t.Errorf("%s: mode %o not restored", p, fi.Mode().Perm())
}
}
}
if ok, _ := Exists(created); ok {
t.Error("file created after the backup was not removed")
}
}
func TestBackupRefusesDirectories(t *testing.T) {
var b Backup
if err := b.Save(t.TempDir()); err == nil {
t.Fatal("expected an error for a directory")
}
}
func TestSame(t *testing.T) {
p := filepath.Join(t.TempDir(), "f")
if Same(p, []byte("x"), 0o640) {
t.Error("missing file reported as same")
}
if err := WriteFile(p, []byte("x"), 0o640, Owner{}); err != nil {
t.Fatal(err)
}
if !Same(p, []byte("x"), 0o640) && runtime.GOOS != "windows" {
t.Error("identical file not recognized")
}
if Same(p, []byte("y"), 0o640) {
t.Error("different content reported as same")
}
if runtime.GOOS != "windows" && Same(p, []byte("x"), 0o600) {
t.Error("different mode reported as same")
}
}
func TestMkdirLike(t *testing.T) {
ref := filepath.Join(t.TempDir(), "zones")
if err := os.Mkdir(ref, 0o750); err != nil {
t.Fatal(err)
}
if err := os.Chmod(ref, 0o770); err != nil {
t.Fatal(err)
}
sub := filepath.Join(ref, "secondary")
if err := MkdirLike(sub, ref); err != nil {
t.Fatal(err)
}
fi, err := os.Stat(sub)
if err != nil || !fi.IsDir() {
t.Fatalf("not created: %v", err)
}
if runtime.GOOS != "windows" && fi.Mode().Perm() != 0o770 {
t.Errorf("mode = %o, want 770", fi.Mode().Perm())
}
// Existing directories stay as they are (content included).
if err := os.WriteFile(filepath.Join(sub, "db.x"), []byte("x"), 0o600); err != nil {
t.Fatal(err)
}
if err := MkdirLike(sub, ref); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(sub, "db.x")); err != nil {
t.Error("content of the existing directory changed")
}
// A file in the way and a missing reference are errors.
file := filepath.Join(ref, "file")
if err := os.WriteFile(file, nil, 0o600); err != nil {
t.Fatal(err)
}
if MkdirLike(file, ref) == nil {
t.Error("file accepted as directory")
}
if MkdirLike(filepath.Join(ref, "other"), filepath.Join(ref, "missing")) == nil {
t.Error("missing reference accepted")
}
if MkdirLike(filepath.Join(ref, "other"), file) == nil {
t.Error("file accepted as reference")
}
}
func TestRequireDir(t *testing.T) {
dir := t.TempDir()
if err := RequireDir(dir); err != nil {
t.Fatal(err)
}
f := filepath.Join(dir, "f")
_ = os.WriteFile(f, nil, 0o600)
if RequireDir(f) == nil || RequireDir(filepath.Join(dir, "nope")) == nil {
t.Fatal("expected errors")
}
}