github.com/jfrog/jfrog-cli-platform-services@v1.2.0/commands/list_cmd_test.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "errors" 8 "net/http" 9 "net/http/httptest" 10 "os" 11 "regexp" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 19 "github.com/jfrog/jfrog-cli-platform-services/model" 20 ) 21 22 func TestListCommand(t *testing.T) { 23 tests := []struct { 24 name string 25 commandArgs []string 26 token string 27 serverBehavior listServerStubBehavior 28 wantErr error 29 assertOutput func(t *testing.T, content []byte) 30 }{ 31 { 32 name: "list", 33 serverBehavior: listServerStubBehavior{ 34 existingWorkers: []*model.WorkerDetails{ 35 { 36 Key: "wk-0", 37 Action: model.ActionAfterCreate, 38 Description: "run wk-0", 39 Enabled: true, 40 SourceCode: "export default async () => ({ 'S': 'OK'})", 41 }, 42 }, 43 }, 44 assertOutput: func(t *testing.T, content []byte) { 45 assert.Equalf(t, "wk-0,AFTER_CREATE,run wk-0,true", strings.TrimSpace(string(content)), "invalid csv received") 46 }, 47 }, 48 { 49 name: "list worker of type", 50 commandArgs: []string{"AFTER_CREATE"}, 51 serverBehavior: listServerStubBehavior{ 52 wantAction: "AFTER_CREATE", 53 existingWorkers: []*model.WorkerDetails{ 54 { 55 Key: "wk-0", 56 Action: model.ActionAfterCreate, 57 Description: "run wk-0", 58 Enabled: true, 59 SourceCode: "export default async () => ({ 'S': 'OK'})", 60 }, 61 { 62 Key: "wk-1", 63 Action: model.ActionBeforeDownload, 64 Description: "run wk-1", 65 Enabled: true, 66 SourceCode: "export default async () => ({ 'S': 'OK'})", 67 }, 68 }, 69 }, 70 assertOutput: func(t *testing.T, content []byte) { 71 assert.Equalf(t, "wk-0,AFTER_CREATE,run wk-0,true", strings.TrimSpace(string(content)), "invalid csv received") 72 }, 73 }, 74 { 75 name: "list for JSON", 76 commandArgs: []string{"--" + model.FlagJsonOutput}, 77 serverBehavior: listServerStubBehavior{ 78 existingWorkers: []*model.WorkerDetails{ 79 { 80 Key: "wk-1", 81 Action: model.ActionGenericEvent, 82 Description: "run wk-1", 83 Enabled: false, 84 SourceCode: "export default async () => ({ 'S': 'OK'})", 85 }, 86 }, 87 }, 88 assertOutput: func(t *testing.T, content []byte) { 89 workers := getAllResponse{} 90 require.NoError(t, json.Unmarshal(content, &workers)) 91 assert.Len(t, workers.Workers, 1) 92 assert.Equalf(t, "wk-1", workers.Workers[0].Key, "Key mismatch") 93 assert.Equalf(t, model.ActionGenericEvent, workers.Workers[0].Action, "Action mismatch") 94 assert.Equalf(t, "run wk-1", workers.Workers[0].Description, "Descritption mismatch") 95 assert.Equalf(t, false, workers.Workers[0].Enabled, "Enabled mismatch") 96 assert.Equalf(t, "export default async () => ({ 'S': 'OK'})", workers.Workers[0].SourceCode, "Source Code mismatch") 97 }, 98 }, 99 { 100 name: "fails if timeout exceeds", 101 commandArgs: []string{"--" + model.FlagTimeout, "500"}, 102 serverBehavior: listServerStubBehavior{ 103 waitFor: 5 * time.Second, 104 }, 105 wantErr: errors.New("request timed out after 500ms"), 106 }, 107 { 108 name: "fails if invalid timeout", 109 commandArgs: []string{"--" + model.FlagTimeout, "abc"}, 110 wantErr: errors.New("invalid timeout provided"), 111 }, 112 } 113 114 for _, tt := range tests { 115 t.Run(tt.name, func(t *testing.T) { 116 ctx, cancelCtx := context.WithCancel(context.Background()) 117 t.Cleanup(cancelCtx) 118 119 runCmd := createCliRunner(t, GetListCommand()) 120 121 err := os.Setenv(model.EnvKeyServerUrl, newListServerStub(t, ctx, &tt.serverBehavior)) 122 require.NoError(t, err) 123 t.Cleanup(func() { 124 _ = os.Unsetenv(model.EnvKeyServerUrl) 125 }) 126 127 if tt.token == "" && tt.serverBehavior.wantBearerToken == "" { 128 tt.token = t.Name() 129 tt.serverBehavior.wantBearerToken = t.Name() 130 } 131 132 err = os.Setenv(model.EnvKeyAccessToken, tt.token) 133 require.NoError(t, err) 134 t.Cleanup(func() { 135 _ = os.Unsetenv(model.EnvKeyAccessToken) 136 }) 137 138 var output bytes.Buffer 139 cliOut = &output 140 t.Cleanup(func() { 141 cliOut = os.Stdout 142 }) 143 144 cmd := append([]string{"worker", "list"}, tt.commandArgs...) 145 146 err = runCmd(cmd...) 147 148 cancelCtx() 149 150 if tt.wantErr == nil { 151 assert.NoError(t, err) 152 } else { 153 assert.EqualError(t, tt.wantErr, err.Error()) 154 } 155 156 if tt.assertOutput != nil { 157 tt.assertOutput(t, output.Bytes()) 158 } 159 }) 160 } 161 } 162 163 var listUrlPattern = regexp.MustCompile(`^/worker/api/v1/workers(/[\S/]+)?$`) 164 165 type listServerStubBehavior struct { 166 waitFor time.Duration 167 responseStatus int 168 wantBearerToken string 169 wantAction string 170 existingWorkers []*model.WorkerDetails 171 } 172 173 type listServerStub struct { 174 t *testing.T 175 ctx context.Context 176 behavior *listServerStubBehavior 177 } 178 179 func newListServerStub(t *testing.T, ctx context.Context, behavior *listServerStubBehavior) string { 180 stub := listServerStub{t: t, behavior: behavior, ctx: ctx} 181 server := httptest.NewUnstartedServer(&stub) 182 t.Cleanup(server.Close) 183 server.Start() 184 return "http:" + "//" + server.Listener.Addr().String() 185 } 186 187 func (s *listServerStub) ServeHTTP(res http.ResponseWriter, req *http.Request) { 188 urlMatch := listUrlPattern.FindAllStringSubmatch(req.URL.Path, -1) 189 if len(urlMatch) == 0 { 190 res.WriteHeader(http.StatusNotFound) 191 return 192 } 193 194 if s.behavior.waitFor > 0 { 195 select { 196 case <-s.ctx.Done(): 197 return 198 case <-time.After(s.behavior.waitFor): 199 } 200 } 201 202 // Validate method 203 if http.MethodGet != req.Method { 204 res.WriteHeader(http.StatusMethodNotAllowed) 205 return 206 } 207 208 // Validate token 209 if req.Header.Get("authorization") != "Bearer "+s.behavior.wantBearerToken { 210 res.WriteHeader(http.StatusForbidden) 211 return 212 } 213 214 if s.behavior.responseStatus > 0 { 215 res.WriteHeader(s.behavior.responseStatus) 216 return 217 } 218 219 var workers []*model.WorkerDetails 220 221 if s.behavior.wantAction == "" { 222 workers = s.behavior.existingWorkers 223 } else { 224 for _, wk := range s.behavior.existingWorkers { 225 if wk.Action == s.behavior.wantAction { 226 workers = append(workers, wk) 227 } 228 } 229 } 230 231 res.WriteHeader(http.StatusOK) 232 _, err := res.Write([]byte(mustJsonMarshal(s.t, getAllResponse{Workers: workers}))) 233 require.NoError(s.t, err) 234 }