package infra import ( "os" "path/filepath" "strings" "testing" ) func TestSSHConfigWrite_CreatesFileAndDir(t *testing.T) { home := t.TempDir() t.Setenv("HOME", home) entries := []SSHConfigEntry{{Alias: "prod", HostName: "10.0.0.1", User: "admin", Port: 22}} if err := SSHConfigWrite(entries); err != nil { t.Fatalf("write: %v", err) } configPath := filepath.Join(home, ".ssh", "config") data, err := os.ReadFile(configPath) if err != nil { t.Fatalf("read back: %v", err) } content := string(data) if !strings.Contains(content, "Host prod") || !strings.Contains(content, "HostName 10.0.0.1") { t.Errorf("unexpected content: %q", content) } info, err := os.Stat(configPath) if err != nil { t.Fatal(err) } if perm := info.Mode().Perm(); perm != 0600 { t.Errorf("expected 0600, got %o", perm) } dirInfo, err := os.Stat(filepath.Join(home, ".ssh")) if err != nil { t.Fatal(err) } if perm := dirInfo.Mode().Perm(); perm != 0700 { t.Errorf("expected dir 0700, got %o", perm) } } func TestSSHConfigWrite_BackupExisting(t *testing.T) { home := t.TempDir() t.Setenv("HOME", home) sshDir := filepath.Join(home, ".ssh") if err := os.MkdirAll(sshDir, 0700); err != nil { t.Fatal(err) } configPath := filepath.Join(sshDir, "config") original := []byte("Host old\n HostName 1.1.1.1\n") if err := os.WriteFile(configPath, original, 0600); err != nil { t.Fatal(err) } entries := []SSHConfigEntry{{Alias: "new", HostName: "2.2.2.2"}} if err := SSHConfigWrite(entries); err != nil { t.Fatalf("write: %v", err) } backup, err := os.ReadFile(filepath.Join(sshDir, "config.bak")) if err != nil { t.Fatalf("backup not found: %v", err) } if string(backup) != string(original) { t.Errorf("backup mismatch: got %q", backup) } current, err := os.ReadFile(configPath) if err != nil { t.Fatal(err) } if !strings.Contains(string(current), "Host new") { t.Errorf("config not overwritten: %q", current) } } func TestSSHConfigWrite_NoBackupWhenAbsent(t *testing.T) { home := t.TempDir() t.Setenv("HOME", home) if err := SSHConfigWrite([]SSHConfigEntry{{Alias: "a"}}); err != nil { t.Fatal(err) } if _, err := os.Stat(filepath.Join(home, ".ssh", "config.bak")); !os.IsNotExist(err) { t.Errorf("expected no backup when config did not exist, stat err=%v", err) } } func TestSSHConfigWriteRead_Roundtrip(t *testing.T) { home := t.TempDir() t.Setenv("HOME", home) original := []SSHConfigEntry{ {Alias: "prod", HostName: "10.0.0.1", User: "admin", Port: 22, IdentityFile: "~/.ssh/id_prod"}, {Alias: "staging", HostName: "10.0.0.2", User: "deploy", Port: 2222}, } if err := SSHConfigWrite(original); err != nil { t.Fatal(err) } parsed, err := SSHConfigRead() if err != nil { t.Fatal(err) } if len(parsed) != len(original) { t.Fatalf("expected %d entries, got %d", len(original), len(parsed)) } for i := range original { if parsed[i].Alias != original[i].Alias || parsed[i].HostName != original[i].HostName || parsed[i].User != original[i].User || parsed[i].Port != original[i].Port { t.Errorf("roundtrip[%d] mismatch: %+v vs %+v", i, parsed[i], original[i]) } } }