package pipelines import ( "image" "os" "path/filepath" "testing" "github.com/geplauder/lithium/storage" "github.com/stretchr/testify/assert" ) // pipeline deserialization func TestPipelineDeserialization(t *testing.T) { t.Run("Image pipeline deserialization is successful", func(t *testing.T) { const Payload string = `{ "name": "example pipeline", "type": 0, "removeMetadata": false, "steps": [ { "name": "resize image", "type": 0 }, { "name": "compress image", "type": 1 } ] }` values := DeserializePipelines([][]byte{[]byte(Payload)}) assert.Equal(t, 1, len(values), "Output should contain one element") assert.Equal(t, "example pipeline", values[0].GetName()) assert.Equal(t, Image, values[0].GetType()) }) t.Run("Video pipelines deserialization is successful", func(t *testing.T) { const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "resize image", "type": 0 }, { "name": "compress image", "type": 1 } ] }` values := DeserializePipelines([][]byte{[]byte(Payload)}) assert.Equal(t, 1, len(values), "Output should contain one element") assert.Equal(t, "example pipeline", values[0].GetName()) assert.Equal(t, Video, values[0].GetType()) }) } // image pipeline steps func TestExecuteSteps(t *testing.T) { t.Run("Pipeline executes with no steps", func(t *testing.T) { const Bucket string = "pipeline_test_01" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image resizing is successful", func(t *testing.T) { const Bucket string = "pipeline_test_02" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "resize image", "type": 0, "options": { "width": 1280, "height": 720, "upscale": false } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 1280, imgConf.Width) assert.Equal(t, 720, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image rotation step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_03" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "rotate image", "type": 1, "options": { "angle": 90.0 } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/800x500.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 500, imgConf.Width) assert.Equal(t, 800, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image flip step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_06" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "flip image", "type": 2, "options": { "direction": "h" } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/800x500.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 800, imgConf.Width) assert.Equal(t, 500, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image flip step direction validation is successful", func(t *testing.T) { const Bucket string = "pipeline_test_07" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "flip image", "type": 2, "options": { "direction": "f" } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/800x500.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps _, err = pipe.Run("source.jpg", Bucket, storageProvider) assert.EqualError(t, err, "invalid flip direction: f") // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) }) t.Run("Image grayscale step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_05" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "grayscale", "type": 3 } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 900, imgConf.Width) assert.Equal(t, 900, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image fit step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_08" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "fit", "type": 4, "options": { "width": 300, "height": 200 } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 200, imgConf.Width) assert.Equal(t, 200, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image invert step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_09" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "invert", "type": 5 } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 900, imgConf.Width) assert.Equal(t, 900, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Image blur step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_10" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "blur", "type": 6, "options": { "sigma": 50.0 } } ] }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // read image config file, err := storageProvider.OpenFile(Bucket, dest) assert.Nil(t, err) imgConf, _, err := image.DecodeConfig(file) assert.Nil(t, err) assert.Equal(t, 900, imgConf.Width) assert.Equal(t, 900, imgConf.Height) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) } // output options func TestEncoding(t *testing.T) { const Bucket string = "pipeline_test_04" const Payload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "resize image", "type": 0, "options": { "width": 1280, "height": 720, "upscale": false } } ], "output": { "quality": 50 } }` t.Run("Image encoding with jpeg quality is successful", func(t *testing.T) { wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps dest, err := pipe.Run("source.jpg", Bucket, storageProvider) assert.Nil(t, err) assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) os.Remove(storageProvider.GetPath(Bucket, dest)) }) t.Run("Wrong output format results in error", func(t *testing.T) { const InvalidPayload string = `{ "name": "example pipeline", "type": 1, "removeMetadata": false, "steps": [ { "name": "resize image", "type": 0, "options": { "width": 1280, "height": 720, "upscale": false } } ], "output": { "format": "foo", "quality": 50 } }` wd, _ := os.Getwd() pipe := DeserializePipelines([][]byte{[]byte(InvalidPayload)})[0] storageProvider := storage.GetFileSystemStorageProvider("test", "..") // copy test file to storage bucket _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg")) assert.Nil(t, err, "Test file should be readable") assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) // run pipeline steps _, err = pipe.Run("source.jpg", Bucket, storageProvider) assert.EqualError(t, err, "output format 'foo' is not supported") // clean up os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) }) }