package filetransfer import ( "context" "testing" "pilotvault/apiserver/internal/plugins" ) func TestDescriptor(t *testing.T) { p := &Plugin{} d := p.Descriptor() if d.Name != "filetransfer" { t.Fatalf("name = %q, want filetransfer", d.Name) } if d.Kind != plugins.KindBuiltin { t.Fatalf("kind = %q, want builtin", d.Kind) } if len(d.Capabilities) == 0 { t.Fatal("expected capabilities") } // Every secret field must be flagged so the manager masks it. for _, f := range d.ConfigFields { if f.Key == "password" || f.Key == "privateKey" || f.Key == "keyPassphrase" { if !f.Secret { t.Errorf("config field %q must be Secret", f.Key) } } } } func TestInitDefaults(t *testing.T) { p := &Plugin{} if err := p.Init(context.Background(), map[string]string{"host": "h", "username": "u"}); err != nil { t.Fatal(err) } if p.protocol != protoSFTP { t.Errorf("default protocol = %q, want sftp", p.protocol) } if p.effectivePort() != 22 { t.Errorf("default sftp port = %d, want 22", p.effectivePort()) } p.protocol = protoFTP if p.effectivePort() != 21 { t.Errorf("default ftp port = %d, want 21", p.effectivePort()) } } func TestResolve(t *testing.T) { p := &Plugin{basePath: "/uploads"} cases := map[string]string{ "": "/uploads", "a/b.txt": "/uploads/a/b.txt", "/etc/abs": "/etc/abs", } for in, want := range cases { if got := p.resolve(in); got != want { t.Errorf("resolve(%q) = %q, want %q", in, got, want) } } } // TestHealthCheckUnreachable confirms an unreachable host is classified as down // (not a panic) — the graceful-failure path Init/HealthCheck must guarantee. func TestHealthCheckUnreachable(t *testing.T) { p := &Plugin{} // Port 1 is reserved and refuses connections quickly. if err := p.Init(context.Background(), map[string]string{ "protocol": protoSFTP, "host": "127.0.0.1", "port": "1", "username": "u", "password": "pw", }); err != nil { t.Fatal(err) } h := p.HealthCheck(context.Background()) if h.Status != plugins.StatusDown { t.Errorf("status = %q, want down (detail=%q)", h.Status, h.Detail) } } func TestHostKeyFingerprintMismatch(t *testing.T) { cb, err := hostKeyChecker("SHA256:doesnotmatch") if err != nil { t.Fatal(err) } if cb == nil { t.Fatal("expected a callback") } } // TestRegistered confirms the plugin registered itself with the shared registry // via init(), so the manager will surface it. func TestRegistered(t *testing.T) { m := plugins.NewManager(t.TempDir() + "/plugins.json") if _, ok := m.Get("filetransfer"); !ok { t.Fatal("filetransfer not registered in the plugin manager") } }