summaryrefslogtreecommitdiffstats
path: root/resource/image_test.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-02-13 21:45:51 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-02-14 20:59:02 +0100
commit58382e9572559f88ed57f5c4899a37d489bcb220 (patch)
tree84a2616485e240f2cf5261e60d79a1bf45ae2b16 /resource/image_test.go
parent53dac9a5067dfd84283a2b2d837738a63b63b596 (diff)
resource: Fix multi-threaded image processing issue
When doing something like this with the same image from a partial used in, say, both the home page and the single page: ```bash {{ with $img }} {{ $big := .Fill "1024x512 top" }} {{ $small := $big.Resize "512x" }} {{ end }} ``` There would be timing issues making Hugo in some cases try to process the same image with the same instructions in parallel. You would experience errors of type: ```bash png: invalid format: not enough pixel data ``` This commit works around that by adding a mutex per image. This should also improve the performance, sligthly, as it avoids duplicate work. The current workaround before this fix is to always operate on the original: ```bash {{ with $img }} {{ $big := .Fill "1024x512 top" }} {{ $small := .Fill "512x256 top" }} {{ end }} ``` Fixes #4404
Diffstat (limited to 'resource/image_test.go')
-rw-r--r--resource/image_test.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/resource/image_test.go b/resource/image_test.go
index de706b0ac..e981a208f 100644
--- a/resource/image_test.go
+++ b/resource/image_test.go
@@ -15,8 +15,12 @@ package resource
import (
"fmt"
+ "math/rand"
+ "strconv"
"testing"
+ "sync"
+
"github.com/stretchr/testify/require"
)
@@ -141,6 +145,51 @@ func TestImageTransformLongFilename(t *testing.T) {
assert.Equal("/a/_hu59e56ffff1bc1d8d122b1403d34e039f_90587_c876768085288f41211f768147ba2647.jpg", resized.RelPermalink())
}
+func TestImageTransformConcurrent(t *testing.T) {
+
+ var wg sync.WaitGroup
+
+ assert := require.New(t)
+
+ spec := newTestResourceOsFs(assert)
+
+ image := fetchImageForSpec(spec, assert, "sunset.jpg")
+
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func(id int) {
+ defer wg.Done()
+ for j := 0; j < 5; j++ {
+ img := image
+ for k := 0; k < 2; k++ {
+ r1, err := img.Resize(fmt.Sprintf("%dx", id-k))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if r1.Width() != id-k {
+ t.Fatalf("Width: %d:%d", r1.Width(), j)
+ }
+
+ r2, err := r1.Resize(fmt.Sprintf("%dx", id-k-1))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = r2.decodeSource()
+ if err != nil {
+ t.Fatal("Err decode:", err)
+ }
+
+ img = r1
+ }
+ }
+ }(i + 20)
+ }
+
+ wg.Wait()
+}
+
func TestDecodeImaging(t *testing.T) {
assert := require.New(t)
m := map[string]interface{}{
@@ -208,3 +257,22 @@ func TestImageWithMetadata(t *testing.T) {
assert.Equal("Sunset #1", resized.Name())
}
+
+func BenchmarkResizeParallel(b *testing.B) {
+ assert := require.New(b)
+ img := fetchSunset(assert)
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ w := rand.Intn(10) + 10
+ resized, err := img.Resize(strconv.Itoa(w) + "x")
+ if err != nil {
+ b.Fatal(err)
+ }
+ _, err = resized.Resize(strconv.Itoa(w-1) + "x")
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}