github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/run/cancel/cancel_test.go (about)

     1  package cancel
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net/http"
     7  	"testing"
     8  
     9  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    10  	"github.com/ungtb10d/cli/v2/pkg/cmd/run/shared"
    11  	workflowShared "github.com/ungtb10d/cli/v2/pkg/cmd/workflow/shared"
    12  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    13  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    14  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    15  	"github.com/ungtb10d/cli/v2/pkg/prompt"
    16  	"github.com/google/shlex"
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  func TestNewCmdCancel(t *testing.T) {
    21  	tests := []struct {
    22  		name     string
    23  		cli      string
    24  		tty      bool
    25  		wants    CancelOptions
    26  		wantsErr bool
    27  	}{
    28  		{
    29  			name: "blank tty",
    30  			tty:  true,
    31  			wants: CancelOptions{
    32  				Prompt: true,
    33  			},
    34  		},
    35  		{
    36  			name:     "blank nontty",
    37  			wantsErr: true,
    38  		},
    39  		{
    40  			name: "with arg",
    41  			cli:  "1234",
    42  			wants: CancelOptions{
    43  				RunID: "1234",
    44  			},
    45  		},
    46  	}
    47  
    48  	for _, tt := range tests {
    49  		t.Run(tt.name, func(t *testing.T) {
    50  			ios, _, _, _ := iostreams.Test()
    51  			ios.SetStdinTTY(tt.tty)
    52  			ios.SetStdoutTTY(tt.tty)
    53  
    54  			f := &cmdutil.Factory{
    55  				IOStreams: ios,
    56  			}
    57  
    58  			argv, err := shlex.Split(tt.cli)
    59  			assert.NoError(t, err)
    60  
    61  			var gotOpts *CancelOptions
    62  			cmd := NewCmdCancel(f, func(opts *CancelOptions) error {
    63  				gotOpts = opts
    64  				return nil
    65  			})
    66  
    67  			cmd.SetArgs(argv)
    68  			cmd.SetIn(&bytes.Buffer{})
    69  			cmd.SetOut(io.Discard)
    70  			cmd.SetErr(io.Discard)
    71  
    72  			_, err = cmd.ExecuteC()
    73  			if tt.wantsErr {
    74  				assert.Error(t, err)
    75  				return
    76  			}
    77  
    78  			assert.NoError(t, err)
    79  
    80  			assert.Equal(t, tt.wants.RunID, gotOpts.RunID)
    81  		})
    82  	}
    83  }
    84  
    85  func TestRunCancel(t *testing.T) {
    86  	inProgressRun := shared.TestRun(1234, shared.InProgress, "")
    87  	completedRun := shared.TestRun(4567, shared.Completed, shared.Failure)
    88  	tests := []struct {
    89  		name      string
    90  		httpStubs func(*httpmock.Registry)
    91  		askStubs  func(*prompt.AskStubber)
    92  		opts      *CancelOptions
    93  		wantErr   bool
    94  		wantOut   string
    95  		errMsg    string
    96  	}{
    97  		{
    98  			name: "cancel run",
    99  			opts: &CancelOptions{
   100  				RunID: "1234",
   101  			},
   102  			wantErr: false,
   103  			httpStubs: func(reg *httpmock.Registry) {
   104  				reg.Register(
   105  					httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/1234"),
   106  					httpmock.JSONResponse(inProgressRun))
   107  				reg.Register(
   108  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   109  					httpmock.JSONResponse(shared.TestWorkflow))
   110  				reg.Register(
   111  					httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/cancel"),
   112  					httpmock.StatusStringResponse(202, "{}"))
   113  			},
   114  			wantOut: "✓ Request to cancel workflow submitted.\n",
   115  		},
   116  		{
   117  			name: "not found",
   118  			opts: &CancelOptions{
   119  				RunID: "1234",
   120  			},
   121  			wantErr: true,
   122  			errMsg:  "Could not find any workflow run with ID 1234",
   123  			httpStubs: func(reg *httpmock.Registry) {
   124  				reg.Register(
   125  					httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/1234"),
   126  					httpmock.StatusStringResponse(404, ""))
   127  			},
   128  		},
   129  		{
   130  			name: "completed",
   131  			opts: &CancelOptions{
   132  				RunID: "4567",
   133  			},
   134  			wantErr: true,
   135  			errMsg:  "Cannot cancel a workflow run that is completed",
   136  			httpStubs: func(reg *httpmock.Registry) {
   137  				reg.Register(
   138  					httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/4567"),
   139  					httpmock.JSONResponse(completedRun))
   140  				reg.Register(
   141  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
   142  					httpmock.JSONResponse(shared.TestWorkflow))
   143  				reg.Register(
   144  					httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/4567/cancel"),
   145  					httpmock.StatusStringResponse(409, ""),
   146  				)
   147  			},
   148  		},
   149  		{
   150  			name: "prompt, no in progress runs",
   151  			opts: &CancelOptions{
   152  				Prompt: true,
   153  			},
   154  			wantErr: true,
   155  			errMsg:  "found no in progress runs to cancel",
   156  			httpStubs: func(reg *httpmock.Registry) {
   157  				reg.Register(
   158  					httpmock.REST("GET", "repos/OWNER/REPO/actions/runs"),
   159  					httpmock.JSONResponse(shared.RunsPayload{
   160  						WorkflowRuns: []shared.Run{
   161  							completedRun,
   162  						},
   163  					}))
   164  				reg.Register(
   165  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
   166  					httpmock.JSONResponse(workflowShared.WorkflowsPayload{
   167  						Workflows: []workflowShared.Workflow{
   168  							shared.TestWorkflow,
   169  						},
   170  					}))
   171  			},
   172  		},
   173  		{
   174  			name: "prompt, cancel",
   175  			opts: &CancelOptions{
   176  				Prompt: true,
   177  			},
   178  			httpStubs: func(reg *httpmock.Registry) {
   179  				reg.Register(
   180  					httpmock.REST("GET", "repos/OWNER/REPO/actions/runs"),
   181  					httpmock.JSONResponse(shared.RunsPayload{
   182  						WorkflowRuns: []shared.Run{
   183  							inProgressRun,
   184  						},
   185  					}))
   186  				reg.Register(
   187  					httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
   188  					httpmock.JSONResponse(workflowShared.WorkflowsPayload{
   189  						Workflows: []workflowShared.Workflow{
   190  							shared.TestWorkflow,
   191  						},
   192  					}))
   193  				reg.Register(
   194  					httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/cancel"),
   195  					httpmock.StatusStringResponse(202, "{}"))
   196  			},
   197  			askStubs: func(as *prompt.AskStubber) {
   198  				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
   199  				as.StubOne(0)
   200  			},
   201  			wantOut: "✓ Request to cancel workflow submitted.\n",
   202  		},
   203  	}
   204  
   205  	for _, tt := range tests {
   206  		reg := &httpmock.Registry{}
   207  		tt.httpStubs(reg)
   208  		tt.opts.HttpClient = func() (*http.Client, error) {
   209  			return &http.Client{Transport: reg}, nil
   210  		}
   211  
   212  		ios, _, stdout, _ := iostreams.Test()
   213  		ios.SetStdoutTTY(true)
   214  		ios.SetStdinTTY(true)
   215  		tt.opts.IO = ios
   216  		tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
   217  			return ghrepo.FromFullName("OWNER/REPO")
   218  		}
   219  
   220  		//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
   221  		as, teardown := prompt.InitAskStubber()
   222  		defer teardown()
   223  		if tt.askStubs != nil {
   224  			tt.askStubs(as)
   225  		}
   226  
   227  		t.Run(tt.name, func(t *testing.T) {
   228  			err := runCancel(tt.opts)
   229  			if tt.wantErr {
   230  				assert.Error(t, err)
   231  				if tt.errMsg != "" {
   232  					assert.Equal(t, tt.errMsg, err.Error())
   233  				}
   234  			} else {
   235  				assert.NoError(t, err)
   236  			}
   237  			assert.Equal(t, tt.wantOut, stdout.String())
   238  			reg.Verify(t)
   239  		})
   240  	}
   241  }