| package main |
| |
| import ( |
| "bytes" |
| "image" |
| "image/png" |
| "io" |
| "io/ioutil" |
| "net/http" |
| "net/http/httptest" |
| "testing" |
| |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/mock" |
| "github.com/stretchr/testify/require" |
| |
| "go.skia.org/infra/go/gcs" |
| "go.skia.org/infra/go/gcs/test_gcsclient" |
| "go.skia.org/infra/go/testutils" |
| "go.skia.org/infra/go/testutils/unittest" |
| ) |
| |
| func TestUploadHandler_ValidJSONFile_Success(t *testing.T) { |
| unittest.SmallTest(t) |
| |
| // This hash is derived from the contents of the input file. |
| const expectedUploadName = "c54ac366e2c358cab4e6431cb47d6178/lottie.json" |
| |
| w := httptest.NewRecorder() |
| r := httptest.NewRequest(http.MethodPost, "/does/not/matter", testutils.GetReader(t, "skottie-luma-matte-request.json")) |
| |
| mgc := test_gcsclient.NewMockClient() |
| |
| optsMatcher := mock.MatchedBy(func(opts gcs.FileWriteOptions) bool { |
| assert.Equal(t, jsonContentType, opts.ContentEncoding) |
| return true |
| }) |
| jsonBuffer := &bytes.Buffer{} |
| mgc.On("FileWriter", testutils.AnyContext, expectedUploadName, optsMatcher).Return(nopCloser(jsonBuffer), nil) |
| |
| srv := Server{ |
| gcsClient: mgc, |
| } |
| srv.uploadHandler(w, r) |
| |
| mgc.AssertExpectations(t) |
| resp := w.Result() |
| assert.Equal(t, http.StatusOK, resp.StatusCode) |
| assert.Equal(t, jsonContentType, resp.Header.Get(contentTypeHeader)) |
| respBody, err := ioutil.ReadAll(resp.Body) |
| require.NoError(t, err) |
| // spot check the return body |
| assert.Contains(t, string(respBody), `"hash":"c54ac366e2c358cab4e6431cb47d6178"`) |
| assert.Len(t, respBody, 3229) |
| // spot check the written data to GCS |
| writtenJSON := jsonBuffer.String() |
| assert.Contains(t, writtenJSON, `"filename":"luma-matte.json"`) |
| assert.Len(t, writtenJSON, 3250) |
| } |
| |
| // The AssetsZip in this test file is a base64 encoded zip file containing 6 small images copied |
| // from the skia repo's //resources/images folder. One of these is a 3x3 png image, which we |
| // make sure is uploaded as a valid PNG file. |
| func TestUploadHandler_ValidJSONWithAssetZip_FilesInZipUploaded(t *testing.T) { |
| unittest.SmallTest(t) |
| |
| // This hash is derived from the contents of the input file. |
| const expectedJSONName = "5f0e05cf5594b23cc98a1a31693a377c/lottie.json" |
| |
| w := httptest.NewRecorder() |
| r := httptest.NewRequest(http.MethodPost, "/does/not/matter", testutils.GetReader(t, "skottie-images-asset.json")) |
| |
| mgc := test_gcsclient.NewMockClient() |
| |
| jsonOptsMatcher := mock.MatchedBy(func(opts gcs.FileWriteOptions) bool { |
| return opts.ContentEncoding == jsonContentType |
| }) |
| jsonBuffer := &bytes.Buffer{} |
| mgc.On("FileWriter", testutils.AnyContext, expectedJSONName, jsonOptsMatcher).Return(nopCloser(jsonBuffer), nil) |
| |
| assetOptsMatcher := mock.MatchedBy(func(opts gcs.FileWriteOptions) bool { |
| return opts.ContentEncoding == octetContentType |
| }) |
| samplePNGBuffer := &bytes.Buffer{} |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/3x3.png", assetOptsMatcher).Return(nopCloser(samplePNGBuffer), nil) |
| // We'll spot check just one of the images for content. The rest we can just make sure |
| // the file names were created correctly. These file names match up with the names of |
| // the files that were zipped up. |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/image_0.png", assetOptsMatcher).Return(newNopWriter(), nil) |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/image_1.png", assetOptsMatcher).Return(newNopWriter(), nil) |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/image_2.png", assetOptsMatcher).Return(newNopWriter(), nil) |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/image_3.png", assetOptsMatcher).Return(newNopWriter(), nil) |
| mgc.On("FileWriter", testutils.AnyContext, "5f0e05cf5594b23cc98a1a31693a377c/assets/image_4.png", assetOptsMatcher).Return(newNopWriter(), nil) |
| |
| srv := Server{ |
| canUploadZips: true, |
| gcsClient: mgc, |
| } |
| srv.uploadHandler(w, r) |
| |
| mgc.AssertExpectations(t) |
| resp := w.Result() |
| assert.Equal(t, http.StatusOK, resp.StatusCode) |
| assert.Equal(t, jsonContentType, resp.Header.Get(contentTypeHeader)) |
| respBody, err := ioutil.ReadAll(resp.Body) |
| require.NoError(t, err) |
| // spot check the return body |
| assert.Contains(t, string(respBody), `"hash":"5f0e05cf5594b23cc98a1a31693a377c"`) |
| assert.Len(t, respBody, 604) |
| |
| writtenJSON := jsonBuffer.String() |
| assert.Contains(t, writtenJSON, `"filename":"skottie-image-asset.json"`) |
| assert.Contains(t, writtenJSON, `"assetsZip":""`) |
| assert.Contains(t, writtenJSON, `"assetsFilename":""`) |
| assert.Len(t, writtenJSON, 634) |
| |
| // Make sure we upload a valid PNG file of size 3x3. |
| pngBytes := samplePNGBuffer.Bytes() |
| img, err := png.Decode(bytes.NewReader(pngBytes)) |
| require.NoError(t, err) |
| assert.Equal(t, image.Rect(0, 0, 3, 3), img.Bounds()) |
| } |
| |
| const ( |
| contentTypeHeader = "Content-Type" |
| jsonContentType = "application/json" |
| octetContentType = "application/octet-stream" |
| ) |
| |
| type nopWriteCloser struct { |
| io.Writer |
| } |
| |
| func (nopWriteCloser) Close() error { return nil } |
| |
| func nopCloser(w io.Writer) io.WriteCloser { |
| return nopWriteCloser{w} |
| } |
| |
| type nopWriter struct{} |
| |
| func (nopWriter) Write(p []byte) (int, error) { |
| return len(p), nil |
| } |
| func newNopWriter() io.WriteCloser { |
| return nopCloser(nopWriter{}) |
| } |