cli/pkg/cmd/secret/delete/delete_test.go
Andy Feller c088951944 Fix host handling in variable and secret delete
This change updates `gh variable delete` and `gh secret delete` to use the host associated with the repository rather than the default host.  Along with these changes is minor refactoring of the tests to ensure appropriate Dotcom vs GHES targeting works as expected.

Minor edit to `gh variable get` testing to simplify some conditional logic in test setup.
2024-08-02 15:11:22 -04:00

353 lines
8.4 KiB
Go

package delete
import (
"bytes"
"net/http"
"testing"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/gh"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewCmdDelete(t *testing.T) {
tests := []struct {
name string
cli string
wants DeleteOptions
wantsErr bool
}{
{
name: "no args",
wantsErr: true,
},
{
name: "repo",
cli: "cool",
wants: DeleteOptions{
SecretName: "cool",
},
},
{
name: "org",
cli: "cool --org anOrg",
wants: DeleteOptions{
SecretName: "cool",
OrgName: "anOrg",
},
},
{
name: "env",
cli: "cool --env anEnv",
wants: DeleteOptions{
SecretName: "cool",
EnvName: "anEnv",
},
},
{
name: "user",
cli: "cool -u",
wants: DeleteOptions{
SecretName: "cool",
UserSecrets: true,
},
},
{
name: "Dependabot repo",
cli: "cool --app Dependabot",
wants: DeleteOptions{
SecretName: "cool",
Application: "Dependabot",
},
},
{
name: "Dependabot org",
cli: "cool --app Dependabot --org UmbrellaCorporation",
wants: DeleteOptions{
SecretName: "cool",
OrgName: "UmbrellaCorporation",
Application: "Dependabot",
},
},
{
name: "Codespaces org",
cli: "cool --app codespaces --org UmbrellaCorporation",
wants: DeleteOptions{
SecretName: "cool",
OrgName: "UmbrellaCorporation",
Application: "Codespaces",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ios, _, _, _ := iostreams.Test()
f := &cmdutil.Factory{
IOStreams: ios,
}
argv, err := shlex.Split(tt.cli)
assert.NoError(t, err)
var gotOpts *DeleteOptions
cmd := NewCmdDelete(f, func(opts *DeleteOptions) error {
gotOpts = opts
return nil
})
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err = cmd.ExecuteC()
if tt.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wants.SecretName, gotOpts.SecretName)
assert.Equal(t, tt.wants.OrgName, gotOpts.OrgName)
assert.Equal(t, tt.wants.EnvName, gotOpts.EnvName)
})
}
}
func Test_removeRun_repo(t *testing.T) {
tests := []struct {
name string
opts *DeleteOptions
host string
httpStubs func(*httpmock.Registry)
}{
{
name: "Actions",
opts: &DeleteOptions{
Application: "actions",
SecretName: "cool_secret",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/actions/secrets/cool_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Actions GHES",
opts: &DeleteOptions{
Application: "actions",
SecretName: "cool_secret",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/actions/secrets/cool_secret"), "example.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Dependabot",
opts: &DeleteOptions{
Application: "dependabot",
SecretName: "cool_dependabot_secret",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/dependabot/secrets/cool_dependabot_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Dependabot GHES",
opts: &DeleteOptions{
Application: "dependabot",
SecretName: "cool_dependabot_secret",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/dependabot/secrets/cool_dependabot_secret"), "example.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "defaults to Actions",
opts: &DeleteOptions{
SecretName: "cool_secret",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/actions/secrets/cool_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
}
for _, tt := range tests {
reg := &httpmock.Registry{}
tt.httpStubs(reg)
defer reg.Verify(t)
ios, _, _, _ := iostreams.Test()
tt.opts.IO = ios
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
err := removeRun(tt.opts)
assert.NoError(t, err)
}
}
func Test_removeRun_env(t *testing.T) {
tests := []struct {
name string
opts *DeleteOptions
host string
httpStubs func(*httpmock.Registry)
}{
{
name: "delete environment secret",
opts: &DeleteOptions{
SecretName: "cool_secret",
EnvName: "development",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/environments/development/secrets/cool_secret"), "api.github.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "delete environment secret GHES",
opts: &DeleteOptions{
SecretName: "cool_secret",
EnvName: "development",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/environments/development/secrets/cool_secret"), "example.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
}
for _, tt := range tests {
reg := &httpmock.Registry{}
tt.httpStubs(reg)
defer reg.Verify(t)
ios, _, _, _ := iostreams.Test()
tt.opts.IO = ios
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
if tt.host != "" {
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
return ghrepo.FromFullName("owner/repo")
}
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
err := removeRun(tt.opts)
require.NoError(t, err)
}
}
func Test_removeRun_org(t *testing.T) {
tests := []struct {
name string
opts *DeleteOptions
wantPath string
}{
{
name: "org",
opts: &DeleteOptions{
OrgName: "UmbrellaCorporation",
},
wantPath: "orgs/UmbrellaCorporation/actions/secrets/tVirus",
},
{
name: "Dependabot org",
opts: &DeleteOptions{
Application: "dependabot",
OrgName: "UmbrellaCorporation",
},
wantPath: "orgs/UmbrellaCorporation/dependabot/secrets/tVirus",
},
{
name: "Codespaces org",
opts: &DeleteOptions{
Application: "codespaces",
OrgName: "UmbrellaCorporation",
},
wantPath: "orgs/UmbrellaCorporation/codespaces/secrets/tVirus",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("DELETE", tt.wantPath),
httpmock.StatusStringResponse(204, "No Content"))
ios, _, _, _ := iostreams.Test()
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("owner/repo")
}
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.IO = ios
tt.opts.SecretName = "tVirus"
err := removeRun(tt.opts)
assert.NoError(t, err)
reg.Verify(t)
})
}
}
func Test_removeRun_user(t *testing.T) {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("DELETE", "user/codespaces/secrets/cool_secret"),
httpmock.StatusStringResponse(204, "No Content"))
ios, _, _, _ := iostreams.Test()
opts := &DeleteOptions{
IO: ios,
HttpClient: func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
},
Config: func() (gh.Config, error) {
return config.NewBlankConfig(), nil
},
SecretName: "cool_secret",
UserSecrets: true,
}
err := removeRun(opts)
assert.NoError(t, err)
reg.Verify(t)
}