github.com/moov-io/imagecashletter@v0.10.1/internal/files/files_test.go (about) 1 // Copyright 2020 The Moov Authors 2 // Use of this source code is governed by an Apache License 3 // license that can be found in the LICENSE file. 4 5 package files 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "net/http" 13 "net/http/httptest" 14 "os" 15 "path/filepath" 16 "strings" 17 "testing" 18 19 "github.com/stretchr/testify/assert" 20 21 "github.com/stretchr/testify/require" 22 23 "github.com/moov-io/base" 24 "github.com/moov-io/imagecashletter" 25 26 "github.com/gorilla/mux" 27 "github.com/moov-io/base/log" 28 ) 29 30 func TestFileId(t *testing.T) { 31 w := httptest.NewRecorder() 32 req := httptest.NewRequest("GET", "/foo", nil) 33 34 fileID := getFileId(w, req) 35 36 assert.Empty(t, fileID) 37 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 38 } 39 40 func TestCashLetterId(t *testing.T) { 41 w := httptest.NewRecorder() 42 req := httptest.NewRequest("GET", "/foo", nil) 43 44 cashLetterID := getCashLetterId(w, req) 45 46 assert.Empty(t, cashLetterID) 47 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 48 } 49 50 func TestFiles_getFiles(t *testing.T) { 51 req := httptest.NewRequest("GET", "/files", nil) 52 repo := &testICLFileRepository{ 53 file: &imagecashletter.File{ 54 ID: base.ID(), 55 }, 56 } 57 router := mux.NewRouter() 58 AppendRoutes(log.NewNopLogger(), router, repo) 59 60 t.Run("returns one file", func(t *testing.T) { 61 w := httptest.NewRecorder() 62 router.ServeHTTP(w, req) 63 w.Flush() 64 65 require.Equal(t, http.StatusOK, w.Code, w.Body) 66 var files []*imagecashletter.File 67 require.NoError(t, json.NewDecoder(w.Body).Decode(&files)) 68 require.Len(t, files, 1) 69 }) 70 71 t.Run("repo error", func(t *testing.T) { 72 w := httptest.NewRecorder() 73 repo.err = errors.New("bad error") 74 router.ServeHTTP(w, req) 75 w.Flush() 76 77 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 78 }) 79 } 80 81 func TestFiles_determineBufferSize(t *testing.T) { 82 env := t.Name() 83 84 size := determineBufferSize(env, 10001) 85 require.Equal(t, 10001, size) 86 87 t.Setenv(env, "452181") 88 89 size = determineBufferSize(env, 10001) 90 require.Equal(t, 452181, size) 91 } 92 93 func TestFiles_createFile(t *testing.T) { 94 w := httptest.NewRecorder() 95 fd, _ := os.Open(filepath.Join("..", "..", "test", "testdata", "valid-ebcdic.x937")) 96 req := httptest.NewRequest("POST", "/files/create", fd) 97 repo := &testICLFileRepository{} 98 router := mux.NewRouter() 99 AppendRoutes(log.NewNopLogger(), router, repo) 100 router.ServeHTTP(w, req) 101 w.Flush() 102 103 require.Equal(t, http.StatusCreated, w.Code, w.Body.String()) 104 105 var resp imagecashletter.File 106 require.NoError(t, json.NewDecoder(w.Body).Decode(&resp)) 107 108 require.Equal(t, "Wave Money", resp.Header.ImmediateDestinationName) 109 110 // error case 111 repo.err = errors.New("bad error") 112 113 w = httptest.NewRecorder() 114 router.ServeHTTP(w, req) 115 w.Flush() 116 117 require.Equal(t, http.StatusBadRequest, w.Code, w.Body.String()) 118 } 119 120 func TestFiles_createFileJSON(t *testing.T) { 121 w := httptest.NewRecorder() 122 fd, _ := os.Open(filepath.Join("..", "..", "test", "testdata", "icl-valid.json")) 123 req := httptest.NewRequest("POST", "/files/create", fd) 124 req.Header.Set("Content-Type", "application/json") 125 repo := &testICLFileRepository{} 126 router := mux.NewRouter() 127 AppendRoutes(log.NewNopLogger(), router, repo) 128 router.ServeHTTP(w, req) 129 w.Flush() 130 131 require.Equal(t, http.StatusCreated, w.Code, w.Body) 132 var resp imagecashletter.File 133 require.NoError(t, json.NewDecoder(w.Body).Decode(&resp)) 134 assert.Equal(t, "US", resp.Header.CountryCode) 135 136 // error case 137 w = httptest.NewRecorder() 138 req = httptest.NewRequest("POST", "/files/create", strings.NewReader("{invalid-json")) 139 req.Header.Set("content-type", "application/json") 140 141 router.ServeHTTP(w, req) 142 w.Flush() 143 144 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 145 } 146 147 func TestFiles_getFile(t *testing.T) { 148 repo := &testICLFileRepository{} 149 router := mux.NewRouter() 150 AppendRoutes(log.NewNopLogger(), router, repo) 151 req := httptest.NewRequest("GET", "/files/foo", nil) 152 153 t.Run("file not found", func(t *testing.T) { 154 w := httptest.NewRecorder() 155 router.ServeHTTP(w, req) 156 w.Flush() 157 158 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 159 }) 160 161 t.Run("successful request", func(t *testing.T) { 162 w := httptest.NewRecorder() 163 repo.file = &imagecashletter.File{ 164 ID: base.ID(), 165 } 166 router.ServeHTTP(w, req) 167 w.Flush() 168 169 require.Equal(t, http.StatusOK, w.Code, w.Body) 170 var file imagecashletter.File 171 require.NoError(t, json.NewDecoder(w.Body).Decode(&file)) 172 assert.NotEmpty(t, file.ID) 173 }) 174 175 t.Run("repo error", func(t *testing.T) { 176 w := httptest.NewRecorder() 177 repo.err = errors.New("bad error") 178 router.ServeHTTP(w, req) 179 w.Flush() 180 181 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 182 }) 183 } 184 185 func TestFiles_updateFileHeader(t *testing.T) { 186 repo := &testICLFileRepository{} 187 router := mux.NewRouter() 188 AppendRoutes(log.NewNopLogger(), router, repo) 189 f := readFile(t, "BNK20180905121042882-A.icl") 190 f.ID = base.ID() 191 192 t.Run("file not found", func(t *testing.T) { 193 var buf bytes.Buffer 194 require.NoError(t, json.NewEncoder(&buf).Encode(f.Header)) 195 w := httptest.NewRecorder() 196 req := httptest.NewRequest("POST", fmt.Sprintf("/files/%s", f.ID), &buf) 197 router.ServeHTTP(w, req) 198 w.Flush() 199 200 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 201 }) 202 203 t.Run("successful request", func(t *testing.T) { 204 var buf bytes.Buffer 205 require.NoError(t, json.NewEncoder(&buf).Encode(f.Header)) 206 w := httptest.NewRecorder() 207 req := httptest.NewRequest("POST", fmt.Sprintf("/files/%s", f.ID), &buf) 208 repo.file = &imagecashletter.File{ 209 ID: f.ID, // create a file without FileHeader so it's updated 210 } 211 router.ServeHTTP(w, req) 212 w.Flush() 213 214 require.Equal(t, http.StatusCreated, w.Code, w.Body) 215 assert.Equal(t, repo.file.Header.CountryCode, f.Header.CountryCode) 216 }) 217 } 218 219 func TestFiles_deleteFile(t *testing.T) { 220 req := httptest.NewRequest("DELETE", "/files/foo", nil) 221 repo := &testICLFileRepository{} 222 router := mux.NewRouter() 223 AppendRoutes(log.NewNopLogger(), router, repo) 224 225 t.Run("file not found", func(t *testing.T) { 226 w := httptest.NewRecorder() 227 router.ServeHTTP(w, req) 228 w.Flush() 229 230 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 231 }) 232 233 t.Run("successful request", func(t *testing.T) { 234 repo.file = &imagecashletter.File{} 235 w := httptest.NewRecorder() 236 router.ServeHTTP(w, req) 237 w.Flush() 238 239 require.Equal(t, http.StatusOK, w.Code, w.Body) 240 }) 241 242 t.Run("repo error", func(t *testing.T) { 243 repo.err = errors.New("bad error") 244 w := httptest.NewRecorder() 245 router.ServeHTTP(w, req) 246 w.Flush() 247 248 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 249 }) 250 251 } 252 253 func TestFiles_getFileContents(t *testing.T) { 254 req := httptest.NewRequest("GET", "/files/foo/contents", nil) 255 router := mux.NewRouter() 256 repo := &testICLFileRepository{} 257 AppendRoutes(log.NewNopLogger(), router, repo) 258 259 t.Run("file not found", func(t *testing.T) { 260 w := httptest.NewRecorder() 261 router.ServeHTTP(w, req) 262 w.Flush() 263 264 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 265 }) 266 267 t.Run("successful request", func(t *testing.T) { 268 w := httptest.NewRecorder() 269 f := readFile(t, "BNK20180905121042882-A.icl") 270 repo.file = f 271 router.ServeHTTP(w, req) 272 w.Flush() 273 274 require.Equal(t, http.StatusOK, w.Code, w.Body) 275 assert.Equal(t, "text/plain", w.Header().Get("Content-Type"), "unexpected content type") 276 }) 277 278 t.Run("repo error", func(t *testing.T) { 279 repo.err = errors.New("bad error") 280 281 w := httptest.NewRecorder() 282 router.ServeHTTP(w, req) 283 w.Flush() 284 285 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 286 }) 287 288 } 289 290 func TestFiles_validateFile(t *testing.T) { 291 req := httptest.NewRequest("GET", "/files/foo/validate", nil) 292 repo := &testICLFileRepository{} 293 router := mux.NewRouter() 294 AppendRoutes(log.NewNopLogger(), router, repo) 295 f := readFile(t, "BNK20180905121042882-A.icl") 296 297 t.Run("file not found", func(t *testing.T) { 298 w := httptest.NewRecorder() 299 router.ServeHTTP(w, req) 300 w.Flush() 301 302 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 303 }) 304 305 t.Run("valid file", func(t *testing.T) { 306 w := httptest.NewRecorder() 307 repo.file = f 308 router.ServeHTTP(w, req) 309 w.Flush() 310 311 require.Equal(t, http.StatusOK, w.Code, w.Body) 312 assert.Contains(t, w.Body.String(), `"{\"error\": null}"`) 313 }) 314 315 t.Run("invalid file", func(t *testing.T) { 316 w := httptest.NewRecorder() 317 // make the file invalid 318 repo.file.Header = imagecashletter.NewFileHeader() 319 router.ServeHTTP(w, req) 320 w.Flush() 321 322 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 323 }) 324 325 t.Run("repo error", func(t *testing.T) { 326 w := httptest.NewRecorder() 327 repo.err = errors.New("bad error") 328 router.ServeHTTP(w, req) 329 w.Flush() 330 331 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 332 }) 333 } 334 335 func TestFiles_addCashLetterToFile(t *testing.T) { 336 repo := &testICLFileRepository{} 337 router := mux.NewRouter() 338 AppendRoutes(log.NewNopLogger(), router, repo) 339 f := readFile(t, "BNK20180905121042882-A.icl") 340 cashLetter := f.CashLetters[0] 341 f.CashLetters = nil 342 343 t.Run("file not found", func(t *testing.T) { 344 var buf bytes.Buffer 345 require.NoError(t, json.NewEncoder(&buf).Encode(cashLetter)) 346 req := httptest.NewRequest("POST", "/files/foo/cashLetters", &buf) 347 w := httptest.NewRecorder() 348 router.ServeHTTP(w, req) 349 w.Flush() 350 351 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 352 }) 353 354 t.Run("successful request", func(t *testing.T) { 355 var buf bytes.Buffer 356 require.NoError(t, json.NewEncoder(&buf).Encode(cashLetter)) 357 req := httptest.NewRequest("POST", "/files/foo/cashLetters", &buf) 358 w := httptest.NewRecorder() 359 repo.file = f 360 router.ServeHTTP(w, req) 361 w.Flush() 362 363 require.Equal(t, http.StatusOK, w.Code, w.Body) 364 var out imagecashletter.File 365 require.NoError(t, json.NewDecoder(w.Body).Decode(&out)) 366 assert.Len(t, out.CashLetters, 1, "expected one cashLetter") 367 }) 368 369 t.Run("repo error", func(t *testing.T) { 370 var buf bytes.Buffer 371 require.NoError(t, json.NewEncoder(&buf).Encode(cashLetter)) 372 req := httptest.NewRequest("POST", "/files/foo/cashLetters", &buf) 373 w := httptest.NewRecorder() 374 repo.file = nil 375 repo.err = errors.New("bad error") 376 router.ServeHTTP(w, req) 377 w.Flush() 378 379 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 380 }) 381 } 382 383 func TestFiles_removeCashLetterFromFile(t *testing.T) { 384 repo := &testICLFileRepository{} 385 router := mux.NewRouter() 386 AppendRoutes(log.NewNopLogger(), router, repo) 387 f := readFile(t, "BNK20180905121042882-A.icl") 388 cashLetterId := base.ID() 389 f.CashLetters[0].ID = cashLetterId 390 req := httptest.NewRequest("DELETE", fmt.Sprintf("/files/foo/cashLetters/%s", cashLetterId), nil) 391 392 t.Run("file not found", func(t *testing.T) { 393 w := httptest.NewRecorder() 394 router.ServeHTTP(w, req) 395 w.Flush() 396 397 require.Equal(t, http.StatusNotFound, w.Code, w.Body) 398 }) 399 400 t.Run("successful request", func(t *testing.T) { 401 w := httptest.NewRecorder() 402 repo.file = f 403 router.ServeHTTP(w, req) 404 w.Flush() 405 406 require.Equal(t, http.StatusOK, w.Code, w.Body) 407 }) 408 409 t.Run("repo error", func(t *testing.T) { 410 w := httptest.NewRecorder() 411 repo.file = nil 412 repo.err = errors.New("bad error") 413 router.ServeHTTP(w, req) 414 w.Flush() 415 416 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 417 }) 418 } 419 420 func TestFiles_createFile_Issue228(t *testing.T) { 421 repo := &testICLFileRepository{} 422 router := mux.NewRouter() 423 AppendRoutes(log.NewNopLogger(), router, repo) 424 425 w := httptest.NewRecorder() 426 fd, _ := os.Open(filepath.Join("..", "..", "test", "testdata", "issue228.json")) 427 req := httptest.NewRequest("POST", "/files/create", fd) 428 req.Header.Set("Content-Type", "application/json") 429 430 router.ServeHTTP(w, req) 431 432 require.Equal(t, http.StatusBadRequest, w.Code, w.Body) 433 type apiError struct { 434 Error string `json:"error"` 435 } 436 var wantErr apiError 437 require.NoError(t, json.Unmarshal(w.Body.Bytes(), &wantErr)) 438 require.Contains(t, wantErr.Error, "CashLetterControl record is mandatory") 439 } 440 441 func readFile(t *testing.T, filename string) *imagecashletter.File { 442 t.Helper() 443 444 fd, err := os.Open(filepath.Join("..", "..", "test", "testdata", filename)) 445 require.NoError(t, err) 446 f, err := imagecashletter.NewReader(fd, imagecashletter.ReadVariableLineLengthOption()).Read() 447 require.NoError(t, err) 448 return &f 449 } 450 451 type testICLFileRepository struct { 452 err error 453 454 file *imagecashletter.File 455 } 456 457 func (r *testICLFileRepository) GetFiles() ([]*imagecashletter.File, error) { 458 if r.err != nil { 459 return nil, r.err 460 } 461 return []*imagecashletter.File{r.file}, nil 462 } 463 464 func (r *testICLFileRepository) GetFile(fileId string) (*imagecashletter.File, error) { 465 if r.err != nil { 466 return nil, r.err 467 } 468 return r.file, nil 469 } 470 471 func (r *testICLFileRepository) SaveFile(file *imagecashletter.File) error { 472 if r.err == nil { // only persist if we're not error'ing 473 r.file = file 474 } 475 return r.err 476 } 477 478 func (r *testICLFileRepository) DeleteFile(fileId string) error { 479 return r.err 480 }