Add tests for secret commands
Co-authored-by: William Martin <williammartin@github.com>
This commit is contained in:
parent
88988374b5
commit
57c9ee0ad2
4 changed files with 427 additions and 1 deletions
|
|
@ -5,6 +5,8 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
ghContext "github.com/cli/cli/v2/context"
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/gh"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
|
|
@ -351,3 +353,119 @@ func Test_removeRun_user(t *testing.T) {
|
|||
|
||||
reg.Verify(t)
|
||||
}
|
||||
|
||||
func Test_removeRun_remote_validation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *DeleteOptions
|
||||
wantPath string
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "single repo detected",
|
||||
opts: &DeleteOptions{
|
||||
Application: "actions",
|
||||
SecretName: "cool_secret",
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
}, nil
|
||||
}},
|
||||
wantPath: "repos/owner/repo/actions/secrets/cool_secret",
|
||||
},
|
||||
{
|
||||
name: "multi repo detected",
|
||||
opts: &DeleteOptions{
|
||||
Application: "actions",
|
||||
SecretName: "cool_secret",
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
}},
|
||||
wantErr: true,
|
||||
errMsg: "multiple remotes detected [origin upstream]. please specify which repo to use by providing the -R or --repo argument",
|
||||
},
|
||||
{
|
||||
name: "multi repo detected - single repo given",
|
||||
opts: &DeleteOptions{
|
||||
Application: "actions",
|
||||
SecretName: "cool_secret",
|
||||
HasRepoOverride: true,
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
}},
|
||||
wantPath: "repos/owner/repo/actions/secrets/cool_secret",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
reg := &httpmock.Registry{}
|
||||
|
||||
if tt.wantPath != "" {
|
||||
reg.Register(
|
||||
httpmock.REST("DELETE", tt.wantPath),
|
||||
httpmock.StatusStringResponse(204, "No Content"))
|
||||
}
|
||||
|
||||
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.FromFullName("owner/repo")
|
||||
}
|
||||
|
||||
err := removeRun(tt.opts)
|
||||
if tt.wantErr {
|
||||
assert.EqualError(t, err, tt.errMsg)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
reg.Verify(t)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
ghContext "github.com/cli/cli/v2/context"
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/gh"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
|
|
@ -442,6 +444,173 @@ func Test_listRun(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_listRunRemoteValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tty bool
|
||||
json bool
|
||||
opts *ListOptions
|
||||
wantOut []string
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "single repo detected",
|
||||
tty: false,
|
||||
opts: &ListOptions{
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantOut: []string{
|
||||
"SECRET_ONE\t1988-10-11T00:00:00Z",
|
||||
"SECRET_TWO\t2020-12-04T00:00:00Z",
|
||||
"SECRET_THREE\t1975-11-30T00:00:00Z",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multi repo detected",
|
||||
tty: false,
|
||||
opts: &ListOptions{
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantOut: []string{},
|
||||
wantErr: true,
|
||||
errMsg: "multiple remotes detected [origin upstream]. please specify which repo to use by providing the -R or --repo argument",
|
||||
},
|
||||
{
|
||||
name: "multi repo detected - single repo given",
|
||||
tty: false,
|
||||
opts: &ListOptions{
|
||||
HasRepoOverride: true,
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantOut: []string{
|
||||
"SECRET_ONE\t1988-10-11T00:00:00Z",
|
||||
"SECRET_TWO\t2020-12-04T00:00:00Z",
|
||||
"SECRET_THREE\t1975-11-30T00:00:00Z",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
reg.Verify(t)
|
||||
|
||||
path := "repos/owner/repo/actions/secrets"
|
||||
|
||||
t0, _ := time.Parse("2006-01-02", "1988-10-11")
|
||||
t1, _ := time.Parse("2006-01-02", "2020-12-04")
|
||||
t2, _ := time.Parse("2006-01-02", "1975-11-30")
|
||||
payload := struct {
|
||||
Secrets []Secret
|
||||
}{
|
||||
Secrets: []Secret{
|
||||
{
|
||||
Name: "SECRET_ONE",
|
||||
UpdatedAt: t0,
|
||||
},
|
||||
{
|
||||
Name: "SECRET_TWO",
|
||||
UpdatedAt: t1,
|
||||
},
|
||||
{
|
||||
Name: "SECRET_THREE",
|
||||
UpdatedAt: t2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
reg.Register(httpmock.REST("GET", path), httpmock.JSONResponse(payload))
|
||||
|
||||
ios, _, stdout, _ := iostreams.Test()
|
||||
|
||||
ios.SetStdoutTTY(tt.tty)
|
||||
|
||||
tt.opts.IO = ios
|
||||
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.Config = func() (gh.Config, error) {
|
||||
return config.NewBlankConfig(), nil
|
||||
}
|
||||
tt.opts.Now = func() time.Time {
|
||||
t, _ := time.Parse(time.RFC822, "15 Mar 23 00:00 UTC")
|
||||
return t
|
||||
}
|
||||
|
||||
if tt.json {
|
||||
exporter := cmdutil.NewJSONExporter()
|
||||
exporter.SetFields(secretFields)
|
||||
tt.opts.Exporter = exporter
|
||||
}
|
||||
|
||||
err := listRun(tt.opts)
|
||||
if tt.wantErr {
|
||||
assert.EqualError(t, err, tt.errMsg)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
if len(tt.wantOut) > 1 {
|
||||
expected := fmt.Sprintf("%s\n", strings.Join(tt.wantOut, "\n"))
|
||||
assert.Equal(t, expected, stdout.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test_listRun_populatesNumSelectedReposIfRequired asserts that NumSelectedRepos
|
||||
// field is populated **only** when it's going to be presented in the output. Since
|
||||
// populating this field costs further API requests (one per secret), it's important
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
ghContext "github.com/cli/cli/v2/context"
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/gh"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
|
|
@ -700,6 +702,143 @@ func Test_getSecretsFromOptions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_setRun_remote_validation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *SetOptions
|
||||
wantApp string
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "single repo detected",
|
||||
opts: &SetOptions{
|
||||
Application: "actions",
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantApp: "actions",
|
||||
},
|
||||
{
|
||||
name: "multi repo detected",
|
||||
opts: &SetOptions{
|
||||
Application: "actions",
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
errMsg: "multiple remotes detected [origin upstream]. please specify which repo to use by providing the -R or --repo argument",
|
||||
},
|
||||
{
|
||||
name: "multi repo detected - single repo given",
|
||||
opts: &SetOptions{
|
||||
Application: "actions",
|
||||
HasRepoOverride: true,
|
||||
Remotes: func() (ghContext.Remotes, error) {
|
||||
remote := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "origin",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
remote2 := &ghContext.Remote{
|
||||
Remote: &git.Remote{
|
||||
Name: "upstream",
|
||||
},
|
||||
Repo: ghrepo.New("owner", "repo"),
|
||||
}
|
||||
|
||||
return ghContext.Remotes{
|
||||
remote,
|
||||
remote2,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantApp: "actions",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
|
||||
if tt.wantApp != "" {
|
||||
reg.Register(httpmock.REST("GET", fmt.Sprintf("repos/owner/repo/%s/secrets/public-key", tt.wantApp)),
|
||||
httpmock.JSONResponse(PubKey{ID: "123", Key: "CDjXqf7AJBXWhMczcy+Fs7JlACEptgceysutztHaFQI="}))
|
||||
|
||||
reg.Register(httpmock.REST("PUT", fmt.Sprintf("repos/owner/repo/%s/secrets/cool_secret", tt.wantApp)),
|
||||
httpmock.StatusStringResponse(201, `{}`))
|
||||
}
|
||||
|
||||
ios, _, _, _ := iostreams.Test()
|
||||
|
||||
opts := &SetOptions{
|
||||
HttpClient: func() (*http.Client, error) {
|
||||
return &http.Client{Transport: reg}, nil
|
||||
},
|
||||
Config: func() (gh.Config, error) { return config.NewBlankConfig(), nil },
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.FromFullName("owner/repo")
|
||||
},
|
||||
IO: ios,
|
||||
SecretName: "cool_secret",
|
||||
Body: "a secret",
|
||||
RandomOverride: fakeRandom,
|
||||
Application: tt.opts.Application,
|
||||
HasRepoOverride: tt.opts.HasRepoOverride,
|
||||
Remotes: tt.opts.Remotes,
|
||||
}
|
||||
|
||||
err := setRun(opts)
|
||||
if tt.wantErr {
|
||||
assert.EqualError(t, err, tt.errMsg)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
reg.Verify(t)
|
||||
|
||||
if tt.wantApp != "" && !tt.wantErr {
|
||||
data, err := io.ReadAll(reg.Requests[1].Body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var payload SecretPayload
|
||||
err = json.Unmarshal(data, &payload)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, payload.KeyID, "123")
|
||||
assert.Equal(t, payload.EncryptedValue, "UKYUCbHd0DJemxa3AOcZ6XcsBwALG9d4bpB8ZT0gSV39vl3BHiGSgj8zJapDxgB2BwqNqRhpjC4=")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fakeRandom() io.Reader {
|
||||
return bytes.NewReader(bytes.Repeat([]byte{5}, 32))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func MutuallyExclusive(message string, conditions ...bool) error {
|
|||
}
|
||||
|
||||
func ValidateHasOnlyOneRemote(hasRepoOverride bool, remotes func() (ghContext.Remotes, error)) error {
|
||||
if !hasRepoOverride {
|
||||
if !hasRepoOverride && remotes != nil {
|
||||
remotes, err := remotes()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue