github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/run/rerun/rerun_test.go (about) 1 package rerun 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "net/http" 7 "testing" 8 9 "github.com/andrewhsu/cli/v2/internal/ghrepo" 10 "github.com/andrewhsu/cli/v2/pkg/cmd/run/shared" 11 "github.com/andrewhsu/cli/v2/pkg/cmdutil" 12 "github.com/andrewhsu/cli/v2/pkg/httpmock" 13 "github.com/andrewhsu/cli/v2/pkg/iostreams" 14 "github.com/andrewhsu/cli/v2/pkg/prompt" 15 "github.com/google/shlex" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestNewCmdRerun(t *testing.T) { 20 tests := []struct { 21 name string 22 cli string 23 tty bool 24 wants RerunOptions 25 wantsErr bool 26 }{ 27 { 28 name: "blank nontty", 29 wantsErr: true, 30 }, 31 { 32 name: "blank tty", 33 tty: true, 34 wants: RerunOptions{ 35 Prompt: true, 36 }, 37 }, 38 { 39 name: "with arg nontty", 40 cli: "1234", 41 wants: RerunOptions{ 42 RunID: "1234", 43 }, 44 }, 45 { 46 name: "with arg tty", 47 tty: true, 48 cli: "1234", 49 wants: RerunOptions{ 50 RunID: "1234", 51 }, 52 }, 53 } 54 55 for _, tt := range tests { 56 t.Run(tt.name, func(t *testing.T) { 57 io, _, _, _ := iostreams.Test() 58 io.SetStdinTTY(tt.tty) 59 io.SetStdoutTTY(tt.tty) 60 61 f := &cmdutil.Factory{ 62 IOStreams: io, 63 } 64 65 argv, err := shlex.Split(tt.cli) 66 assert.NoError(t, err) 67 68 var gotOpts *RerunOptions 69 cmd := NewCmdRerun(f, func(opts *RerunOptions) error { 70 gotOpts = opts 71 return nil 72 }) 73 cmd.SetArgs(argv) 74 cmd.SetIn(&bytes.Buffer{}) 75 cmd.SetOut(ioutil.Discard) 76 cmd.SetErr(ioutil.Discard) 77 78 _, err = cmd.ExecuteC() 79 if tt.wantsErr { 80 assert.Error(t, err) 81 return 82 } 83 84 assert.NoError(t, err) 85 86 assert.Equal(t, tt.wants.RunID, gotOpts.RunID) 87 assert.Equal(t, tt.wants.Prompt, gotOpts.Prompt) 88 }) 89 } 90 91 } 92 93 func TestRerun(t *testing.T) { 94 tests := []struct { 95 name string 96 httpStubs func(*httpmock.Registry) 97 askStubs func(*prompt.AskStubber) 98 opts *RerunOptions 99 tty bool 100 wantErr bool 101 errOut string 102 wantOut string 103 }{ 104 { 105 name: "arg", 106 tty: true, 107 opts: &RerunOptions{ 108 RunID: "1234", 109 }, 110 httpStubs: func(reg *httpmock.Registry) { 111 reg.Register( 112 httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/1234"), 113 httpmock.JSONResponse(shared.FailedRun)) 114 reg.Register( 115 httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/rerun"), 116 httpmock.StringResponse("{}")) 117 }, 118 wantOut: "✓ Requested rerun of run 1234\n", 119 }, 120 { 121 name: "prompt", 122 tty: true, 123 opts: &RerunOptions{ 124 Prompt: true, 125 }, 126 httpStubs: func(reg *httpmock.Registry) { 127 reg.Register( 128 httpmock.REST("GET", "repos/OWNER/REPO/actions/runs"), 129 httpmock.JSONResponse(shared.RunsPayload{ 130 WorkflowRuns: shared.TestRuns, 131 })) 132 reg.Register( 133 httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/1234"), 134 httpmock.JSONResponse(shared.FailedRun)) 135 reg.Register( 136 httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/rerun"), 137 httpmock.StringResponse("{}")) 138 }, 139 askStubs: func(as *prompt.AskStubber) { 140 as.StubOne(2) 141 }, 142 wantOut: "✓ Requested rerun of run 1234\n", 143 }, 144 { 145 name: "prompt but no failed runs", 146 tty: true, 147 opts: &RerunOptions{ 148 Prompt: true, 149 }, 150 httpStubs: func(reg *httpmock.Registry) { 151 reg.Register( 152 httpmock.REST("GET", "repos/OWNER/REPO/actions/runs"), 153 httpmock.JSONResponse(shared.RunsPayload{ 154 WorkflowRuns: []shared.Run{ 155 shared.SuccessfulRun, 156 shared.TestRun("in progress", 2, shared.InProgress, ""), 157 }})) 158 }, 159 wantErr: true, 160 errOut: "no recent runs have failed; please specify a specific run ID", 161 }, 162 { 163 name: "unrerunnable", 164 tty: true, 165 opts: &RerunOptions{ 166 RunID: "3", 167 }, 168 httpStubs: func(reg *httpmock.Registry) { 169 reg.Register( 170 httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/3"), 171 httpmock.JSONResponse(shared.SuccessfulRun)) 172 reg.Register( 173 httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/3/rerun"), 174 httpmock.StatusStringResponse(403, "no")) 175 }, 176 wantErr: true, 177 errOut: "run 3 cannot be rerun; its workflow file may be broken.", 178 }, 179 } 180 181 for _, tt := range tests { 182 reg := &httpmock.Registry{} 183 tt.httpStubs(reg) 184 tt.opts.HttpClient = func() (*http.Client, error) { 185 return &http.Client{Transport: reg}, nil 186 } 187 188 io, _, stdout, _ := iostreams.Test() 189 io.SetStdinTTY(tt.tty) 190 io.SetStdoutTTY(tt.tty) 191 tt.opts.IO = io 192 tt.opts.BaseRepo = func() (ghrepo.Interface, error) { 193 return ghrepo.FromFullName("OWNER/REPO") 194 } 195 196 as, teardown := prompt.InitAskStubber() 197 defer teardown() 198 if tt.askStubs != nil { 199 tt.askStubs(as) 200 } 201 202 t.Run(tt.name, func(t *testing.T) { 203 err := runRerun(tt.opts) 204 if tt.wantErr { 205 assert.Error(t, err) 206 assert.Equal(t, tt.errOut, err.Error()) 207 return 208 } 209 assert.NoError(t, err) 210 assert.Equal(t, tt.wantOut, stdout.String()) 211 reg.Verify(t) 212 }) 213 } 214 }