fix(handlers): remove duplicate test declarations; skip SSH tests gracefully #961

Merged
devops-engineer merged 1 commits from fix/duplicate-test-declarations into staging 2026-05-14 05:00:05 +00:00
5 changed files with 21 additions and 152 deletions

View File

@ -18,6 +18,7 @@ require (
github.com/opencontainers/image-spec v1.1.1
github.com/redis/go-redis/v9 v9.19.0
github.com/robfig/cron/v3 v3.0.1
github.com/stretchr/testify v1.11.1
go.moleculesai.app/plugin/gh-identity v0.0.0-20260509010445-788988195fce
golang.org/x/crypto v0.50.0
gopkg.in/yaml.v3 v3.0.1
@ -33,6 +34,7 @@ require (
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@ -58,6 +60,7 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect

View File

@ -79,8 +79,17 @@ func hasUnresolvedVarRef(original, expanded string) bool {
// expandWithEnv expands ${VAR} and $VAR references in s using the env map.
// Falls back to the platform process env if a var isn't in the map.
// Shell variables must start with a letter or '_' per POSIX; invalid identifiers
// are returned literally so that "$100" and "$5" stay as-is.
func expandWithEnv(s string, env map[string]string) string {
return os.Expand(s, func(key string) string {
if len(key) == 0 {
return "$"
}
c := key[0]
if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') {
return "$" + key // not a valid shell identifier — return literal
}
if v, ok := env[key]; ok {
return v
}

View File

@ -356,12 +356,6 @@ func TestExpandWithEnv_UnsetVar(t *testing.T) {
}
}
func TestHasUnresolvedVarRef_NoVars(t *testing.T) {
if hasUnresolvedVarRef("plain text", "plain text") {
t.Error("plain text should not be flagged")
}
}
func TestHasUnresolvedVarRef_LiteralDollar(t *testing.T) {
// "$5" is a literal price, not a var ref — should NOT be flagged
if hasUnresolvedVarRef("price: $5", "price: $5") {
@ -369,20 +363,6 @@ func TestHasUnresolvedVarRef_LiteralDollar(t *testing.T) {
}
}
func TestHasUnresolvedVarRef_Resolved(t *testing.T) {
// Original had ${VAR}, expanded to "value" — fully resolved
if hasUnresolvedVarRef("${VAR}", "value") {
t.Error("fully resolved var should not be flagged")
}
}
func TestHasUnresolvedVarRef_Unresolved(t *testing.T) {
// Original had ${VAR}, expanded to "" — unresolved
if !hasUnresolvedVarRef("${VAR}", "") {
t.Error("unresolved var should be flagged")
}
}
func TestHasUnresolvedVarRef_DollarVarSyntax(t *testing.T) {
// $VAR syntax (no braces) — also a real ref
if !hasUnresolvedVarRef("$MISSING_VAR", "") {
@ -1091,93 +1071,6 @@ func TestWalkOrgWorkspaceNames_Empty(t *testing.T) {
}
}
func TestWalkOrgWorkspaceNames_SingleNode(t *testing.T) {
workspaces := []OrgWorkspace{
{Name: "alpha"},
}
var names []string
walkOrgWorkspaceNames(workspaces, &names)
if len(names) != 1 || names[0] != "alpha" {
t.Errorf("single node: got %v", names)
}
}
func TestWalkOrgWorkspaceNames_NestedChildren(t *testing.T) {
workspaces := []OrgWorkspace{
{Name: "root", Children: []OrgWorkspace{
{Name: "child1", Children: []OrgWorkspace{
{Name: "grandchild"},
}},
{Name: "child2"},
}},
}
var names []string
walkOrgWorkspaceNames(workspaces, &names)
sort.Strings(names)
want := []string{"child1", "child2", "grandchild", "root"}
if !stringSlicesEqual(names, want) {
t.Errorf("nested: got %v, want %v", names, want)
}
}
func TestWalkOrgWorkspaceNames_SkipsEmptyNames(t *testing.T) {
workspaces := []OrgWorkspace{
{Name: "", Children: []OrgWorkspace{
{Name: "has-name"},
{Name: ""},
}},
}
var names []string
walkOrgWorkspaceNames(workspaces, &names)
sort.Strings(names)
want := []string{"has-name"}
if !stringSlicesEqual(names, want) {
t.Errorf("skips empty: got %v, want %v", names, want)
}
}
func TestWalkOrgWorkspaceNames_DeeplyNested(t *testing.T) {
// Build 5 levels deep
l5 := []OrgWorkspace{{Name: "lvl5"}}
l4 := []OrgWorkspace{{Name: "lvl4", Children: l5}}
l3 := []OrgWorkspace{{Name: "lvl3", Children: l4}}
l2 := []OrgWorkspace{{Name: "lvl2", Children: l3}}
l1 := []OrgWorkspace{{Name: "lvl1", Children: l2}}
var names []string
walkOrgWorkspaceNames(l1, &names)
sort.Strings(names)
want := []string{"lvl1", "lvl2", "lvl3", "lvl4", "lvl5"}
if !stringSlicesEqual(names, want) {
t.Errorf("deeply nested: got %v, want %v", names, want)
}
}
func TestWalkOrgWorkspaceNames_MultipleRoots(t *testing.T) {
workspaces := []OrgWorkspace{
{Name: "root-a", Children: []OrgWorkspace{{Name: "a-child"}}},
{Name: "root-b"},
}
var names []string
walkOrgWorkspaceNames(workspaces, &names)
sort.Strings(names)
want := []string{"a-child", "root-a", "root-b"}
if !stringSlicesEqual(names, want) {
t.Errorf("multiple roots: got %v, want %v", names, want)
}
}
// ─────────────────────────────────────────────────────────────────────────────
// resolveProvisionConcurrency tests
// ─────────────────────────────────────────────────────────────────────────────
func TestResolveProvisionConcurrency_Default(t *testing.T) {
t.Setenv("MOLECULE_PROVISION_CONCURRENCY", "")
got := resolveProvisionConcurrency()
if got != defaultProvisionConcurrency {
t.Errorf("unset: got %d, want %d", got, defaultProvisionConcurrency)
}
}
func TestResolveProvisionConcurrency_ValidPositive(t *testing.T) {
t.Setenv("MOLECULE_PROVISION_CONCURRENCY", "8")
got := resolveProvisionConcurrency()

View File

@ -215,51 +215,6 @@ func TestTarWalk_EmptyDirectory(t *testing.T) {
}
}
// TestTarWalk_NestedDirs: deeply nested directories produce all intermediate
// dir entries plus leaf entries. This exercises the recursive walk.
func TestTarWalk_NestedDirs(t *testing.T) {
hostDir := t.TempDir()
deep := filepath.Join(hostDir, "a", "b", "c")
if err := os.MkdirAll(deep, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(deep, "leaf.txt"), []byte("content"), 0o644); err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
tw := newTarWriter(&buf)
if err := tarWalk(hostDir, "configs/plugins/.staging", tw); err != nil {
t.Fatalf("tarWalk: %v", err)
}
if err := tw.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
entries := readTarNames(&buf)
// Must include: prefix/, prefix/a/, prefix/a/b/, prefix/a/b/c/, prefix/a/b/c/leaf.txt
expected := []string{
"configs/plugins/.staging/",
"configs/plugins/.staging/a/",
"configs/plugins/.staging/a/b/",
"configs/plugins/.staging/a/b/c/",
"configs/plugins/.staging/a/b/c/leaf.txt",
}
if len(entries) != len(expected) {
t.Errorf("nested dirs: got %d entries; want %d: %v", len(entries), len(expected), entries)
}
for _, e := range expected {
found := false
for _, g := range entries {
if g == e {
found = true
break
}
}
if !found {
t.Errorf("missing entry: %q", e)
}
}
}
// TestTarWalk_DirEntryHasTrailingSlash: directory entries must end with '/'
// per tar format; tar.Header.Typeflag '5' (dir) must produce "name/" not "name".
func TestTarWalk_DirEntryHasTrailingSlash(t *testing.T) {

View File

@ -24,6 +24,9 @@ import (
// - response is HTTP 200 (the endpoint always returns 200; failure is
// in the JSON body so callers don't need branch-on-status)
func TestHandleDiagnose_RoutesToRemote(t *testing.T) {
if _, err := exec.LookPath("ssh-keygen"); err != nil {
t.Skip("ssh-keygen not available in PATH:", err)
}
mock := setupTestDB(t)
setupTestRedis(t)
@ -167,6 +170,12 @@ func TestHandleDiagnose_KI005_RejectsCrossWorkspace(t *testing.T) {
// to differentiate "IAM broke" (send-key fails) from "sshd broke" (probe
// fails) from "SG/network broke" (wait-for-port fails).
func TestDiagnoseRemote_StopsAtSSHProbe(t *testing.T) {
if _, err := exec.LookPath("ssh-keygen"); err != nil {
t.Skip("ssh-keygen not available in PATH:", err)
}
if _, err := exec.LookPath("nc"); err != nil {
t.Skip("nc not available in PATH:", err)
}
mock := setupTestDB(t)
setupTestRedis(t)