cli/pkg/cmd/codespace/list_test.go
doaortu 83322104b7
feat: add web flag for codespace list & create subcommand (#7288)
* feat: add web flag to cs list subcommand

web flag only works with repo flag, because,
currently there only param for listing with repo_id

* feat: add web flag to cs crate subcommand

web flag used for creating codespace through web UI instead of terminal.
web flag cannot be used with display-name, idle-timeout,
or retention retention-period
because there's no option for that in the Web UI

* refactor: extract mutual excusive logic to PreRunE

- changed web flag mutual exclusive logic, using cmdutil
- extract that logic to PreRunE clause in createCmd
- move web flag up to make it close to PreRunE clause (for clarity)
- add new param to newCreateCmd fn to facilitate test logic
- apply new newCreateCmd fn to root.go

* fix: clarify flag desc and error message

- remove 'yet' from error messages that can cause misunderstanding
- clarify list web flag can only be used with repo flag

* fix: skip machine check when we use web flag ...
(..and no machine flag provided)

+ add test for this new case
+ adjust related test cases for this new change.

* refactor: move flag check logic to PreRunE

why: err on PreRunE or RunE will also print help if error happened

+ move web, repo, org, user mutual exclusive logic to PreRunE clause
+ move repo, org, user mutual exclusive logic to PreRunE
+ move limit check flag to PreRunE
+ modify newListCmd fn to facilitate test logic
+ apply new newListCmd to root.go
+ add test cases to check PreRunE clause
- remove mutual exclusive test cases from Test_AppList

* refactor: remove the opts equality checks

* fix: mutually exclusive misfires
because of wrong logic

+ refine test case too

* cleanup:removing useWeb check in fn getMachineName

because it's no longer needed

+ remove redundant test-case

* refactor: remove redundant ifs

* refactor: clarify test name

* re-clarify web flag desc in list.go

* refactor: break long lines, use more idiomatic err

* add test case for nonexistent/wrong machine
2023-04-13 10:37:16 -05:00

249 lines
6.1 KiB
Go

package codespace
import (
"bytes"
"context"
"fmt"
"testing"
"github.com/cli/cli/v2/internal/browser"
"github.com/cli/cli/v2/internal/codespaces/api"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
)
func TestListCmdFlagError(t *testing.T) {
tests := []struct {
name string
args string
wantsErr error
}{
{
name: "list codespaces,--repo, --org and --user flag",
args: "--repo foo/bar --org github --user github",
wantsErr: fmt.Errorf("using `--org` or `--user` with `--repo` is not allowed"),
},
{
name: "list codespaces,--web, --org and --user flag",
args: "--web --org github --user github",
wantsErr: fmt.Errorf("using `--web` with `--org` or `--user` is not supported, please use with `--repo` instead"),
},
{
name: "list codespaces, negative --limit flag",
args: "--limit -1",
wantsErr: fmt.Errorf("invalid limit: -1"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ios, _, _, _ := iostreams.Test()
a := &App{
io: ios,
}
cmd := newListCmd(a)
args, _ := shlex.Split(tt.args)
cmd.SetArgs(args)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err := cmd.ExecuteC()
if tt.wantsErr != nil {
assert.Error(t, err)
assert.EqualError(t, err, tt.wantsErr.Error())
return
}
})
}
}
func TestApp_List(t *testing.T) {
type fields struct {
apiClient apiClient
}
tests := []struct {
name string
fields fields
opts *listOptions
wantError error
wantURL string
}{
{
name: "list codespaces, no flags",
fields: fields{
apiClient: &apiClientMock{
ListCodespacesFunc: func(ctx context.Context, opts api.ListCodespacesOptions) ([]*api.Codespace, error) {
if opts.OrgName != "" {
return nil, fmt.Errorf("should not be called with an orgName")
}
return []*api.Codespace{
{
DisplayName: "CS1",
},
}, nil
},
},
},
opts: &listOptions{},
},
{
name: "list codespaces, --org flag",
fields: fields{
apiClient: &apiClientMock{
ListCodespacesFunc: func(ctx context.Context, opts api.ListCodespacesOptions) ([]*api.Codespace, error) {
if opts.OrgName != "TestOrg" {
return nil, fmt.Errorf("Expected orgName to be TestOrg. Got %s", opts.OrgName)
}
if opts.UserName != "" {
return nil, fmt.Errorf("Expected userName to be blank. Got %s", opts.UserName)
}
return []*api.Codespace{
{
DisplayName: "CS1",
},
}, nil
},
},
},
opts: &listOptions{
orgName: "TestOrg",
},
},
{
name: "list codespaces, --org and --user flag",
fields: fields{
apiClient: &apiClientMock{
ListCodespacesFunc: func(ctx context.Context, opts api.ListCodespacesOptions) ([]*api.Codespace, error) {
if opts.OrgName != "TestOrg" {
return nil, fmt.Errorf("Expected orgName to be TestOrg. Got %s", opts.OrgName)
}
if opts.UserName != "jimmy" {
return nil, fmt.Errorf("Expected userName to be jimmy. Got %s", opts.UserName)
}
return []*api.Codespace{
{
DisplayName: "CS1",
},
}, nil
},
},
},
opts: &listOptions{
orgName: "TestOrg",
userName: "jimmy",
},
},
{
name: "list codespaces, --repo",
fields: fields{
apiClient: &apiClientMock{
ListCodespacesFunc: func(ctx context.Context, opts api.ListCodespacesOptions) ([]*api.Codespace, error) {
if opts.RepoName == "" {
return nil, fmt.Errorf("Expected repository to not be nil")
}
if opts.RepoName != "cli/cli" {
return nil, fmt.Errorf("Expected repository name to be cli/cli. Got %s", opts.RepoName)
}
if opts.OrgName != "" {
return nil, fmt.Errorf("Expected orgName to be blank. Got %s", opts.OrgName)
}
if opts.UserName != "" {
return nil, fmt.Errorf("Expected userName to be blank. Got %s", opts.UserName)
}
return []*api.Codespace{
{
DisplayName: "CS1",
},
}, nil
},
},
},
opts: &listOptions{
repo: "cli/cli",
},
},
{
name: "list codespaces,--web",
opts: &listOptions{
useWeb: true,
},
wantURL: "https://github.com/codespaces",
},
{
name: "list codespaces,--web, --repo flag",
fields: fields{
apiClient: &apiClientMock{
ListCodespacesFunc: func(ctx context.Context, opts api.ListCodespacesOptions) ([]*api.Codespace, error) {
if opts.RepoName == "" {
return nil, fmt.Errorf("Expected repository to not be nil")
}
if opts.RepoName != "cli/cli" {
return nil, fmt.Errorf("Expected repository name to be cli/cli. Got %s", opts.RepoName)
}
if opts.OrgName != "" {
return nil, fmt.Errorf("Expected orgName to be blank. Got %s", opts.OrgName)
}
if opts.UserName != "" {
return nil, fmt.Errorf("Expected userName to be blank. Got %s", opts.UserName)
}
return []*api.Codespace{
{
DisplayName: "CS1",
Repository: api.Repository{ID: 123},
},
}, nil
},
},
},
opts: &listOptions{
useWeb: true,
repo: "cli/cli",
},
wantURL: "https://github.com/codespaces?repository_id=123",
},
}
var b *browser.Stub
var a *App
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ios, _, _, _ := iostreams.Test()
if tt.opts.useWeb {
b = &browser.Stub{}
a = &App{
browser: b,
io: ios,
apiClient: tt.fields.apiClient,
}
} else {
a = &App{
io: ios,
apiClient: tt.fields.apiClient,
}
}
var exporter cmdutil.Exporter
err := a.List(context.Background(), tt.opts, exporter)
if (err != nil) != (tt.wantError != nil) {
t.Errorf("error = %v, wantErr %v", err, tt.wantError)
return
}
if err != nil && err.Error() != tt.wantError.Error() {
t.Errorf("error = %v, wantErr %v", err, tt.wantError)
}
if tt.opts.useWeb {
b.Verify(t, tt.wantURL)
}
})
}
}