0
Fork 0
mirror of https://github.com/willnorris/imageproxy.git synced 2025-04-15 03:03:10 -05:00

DEVOPS-677: Updates tests to fit TWM needs

This commit is contained in:
Ken Kelly 2023-10-12 14:19:30 -04:00
parent ddd4375765
commit 02b81763ea
7 changed files with 99 additions and 25 deletions

View file

@ -1,33 +1,30 @@
FROM golang:1.15 as build
RUN useradd -u 1001 go
WORKDIR /go/src/willnorris.com/go/imageproxy
ADD . .
WORKDIR /app
#WORKDIR /go/src/willnorris.com/go/imageproxy/cmd/imageproxy
COPY go.mod go.sum ./
COPY third_party/envy/go.mod ./third_party/envy/
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -v ./cmd/imageproxy
RUN CGO_ENABLED=0 GOOS=linux go install -v ./cmd/imageproxy
FROM alpine:3.14
RUN apk update && apk add pngquant jpegoptim libwebp-tools
COPY --from=build /etc/passwd /etc/passwd
WORKDIR /go/bin
COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
USER go
COPY --from=build /etc/ssl/certs /etc/ssl/certs
COPY --from=build /go/bin/imageproxy .
COPY --from=build /go/src/willnorris.com/go/imageproxy/indicators-size /indicators-size
COPY --from=build /go/src/willnorris.com/go/imageproxy/assets /assets
CMD ["-addr", "0.0.0.0:8080"]
ENTRYPOINT ["/go/bin/imageproxy"]
CMD ["-verbose", "true"]
ENTRYPOINT ["/go/bin/imageproxy", "-scaleUp"]
EXPOSE 8080

View file

@ -154,10 +154,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
timer := prometheus.NewTimer(metricRequestDuration)
defer timer.ObserveDuration()
start := time.Now()
h.ServeHTTP(w, r)
httpRequestsResponseTime.Observe(float64(time.Since(start).Seconds()))
}
// serveImage handles incoming requests for proxied images.
@ -198,7 +195,6 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
p.log(msg)
http.Error(w, msg, http.StatusInternalServerError)
metricRemoteErrors.Inc()
remoteImageFetchErrors.Inc()
return
}
// close the original resp.Body, even if we wrap it in a NopCloser below
@ -208,7 +204,7 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
msg := fmt.Sprintf("remote image not found: %v", req.String())
log.Print(msg)
http.Error(w, msg, http.StatusNotFound)
remoteImageFetchErrors.Inc()
metricRemoteErrors.Inc()
return
}
@ -220,10 +216,9 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
if cached {
metricServedFromCache.Inc()
requestServedFromCacheCount.Inc()
}
copyHeader(w.Header(), resp.Header, "Cache-Control", "Last-Modified", "Expires", "Etag", "Link")
copyHeader(w.Header(), resp.Header, "Cache-Control", "Expires", "Etag", "Link")
if should304(r, resp) {
w.WriteHeader(http.StatusNotModified)
@ -233,6 +228,8 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
contentType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if contentType == "" || contentType == "application/octet-stream" || contentType == "binary/octet-stream" {
fmt.Println(fmt.Sprintf("requested image content type (%s) isn't valid, need to peek: %s", contentType, req.String()))
// try to detect content type
b := bufio.NewReader(resp.Body)
resp.Body = ioutil.NopCloser(b)
@ -245,7 +242,7 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
return
}
if resp.ContentLength != 0 && !validContentType(p.ContentTypes, contentType) {
if resp.ContentLength != 0 && !contentTypeMatches(p.ContentTypes, contentType) {
msg := fmt.Sprintf("forbidden content-type: %q", contentType)
log.Print(msg)
http.Error(w, msg, http.StatusForbidden)
@ -270,6 +267,12 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
// peekContentType peeks at the first 512 bytes of p, and attempts to detect
// the content type. Returns empty string if error occurs.
func peekContentType(p *bufio.Reader) string {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered in peekContentType", r)
}
}()
byt, err := p.Peek(512)
if err != nil && err != bufio.ErrBufferFull && err != io.EOF {
return ""
@ -419,6 +422,7 @@ func should304(req *http.Request, resp *http.Response) bool {
// TODO(willnorris): if-none-match header can be a comma separated list
// of multiple tags to be matched, or the special value "*" which
// matches all etags
etag := resp.Header.Get("Etag")
if etag != "" && etag == req.Header.Get("If-None-Match") {
return true

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
test-images/unanime-400x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
test-images/unanime.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View file

@ -91,6 +91,7 @@ func Transform(img []byte, opt Options) ([]byte, error) {
if err != nil {
return nil, err
}
outputBytes = buf.Bytes()
case "gif":
fn := func(img image.Image) image.Image {
return transformImage(img, opt)
@ -107,6 +108,7 @@ func Transform(img []byte, opt Options) ([]byte, error) {
}
m = transformImage(m, opt)
err = jpeg.Encode(buf, m, &jpeg.Options{Quality: quality})
if err != nil {
return nil, err
@ -304,7 +306,7 @@ func cropParams(m image.Image, opt Options) image.Rectangle {
return image.Rect(x0, y0, x1, y1)
}
//make image square by adding transparency to max side
// make image square by adding transparency to max side
func makeSquare(m image.Image, sidePadding int) image.Image {
x := m.Bounds().Dx()
x = x + sidePadding
@ -376,6 +378,9 @@ func exifOrientation(r io.Reader) (opt Options) {
func addSizeIndicator(m image.Image, size string) image.Image {
relativePath := "../.."
if os.Getenv("GOTESTS") == "true" {
relativePath = "./"
}
if os.Getenv("DOCKER") == "true" {
relativePath = ""
}
@ -431,7 +436,6 @@ func transformImage(m image.Image, opt Options) image.Image {
// Parse crop and resize parameters before applying any transforms.
// This is to ensure that any percentage-based values are based off the
// size of the original image.
start := time.Now()
rect := cropParams(m, opt)
w, h, resize := resizeParams(m, opt)
@ -478,7 +482,5 @@ func transformImage(m image.Image, opt Options) image.Image {
m = addSizeIndicator(m, opt.IndicatorSize)
}
imageTransformationSummary.Observe(float64(time.Since(start).Seconds()))
return m
}

View file

@ -15,8 +15,11 @@
package imageproxy
import (
"bufio"
"bytes"
"encoding/base64"
"fmt"
"golang.org/x/image/bmp"
"image"
"image/color"
"image/draw"
@ -24,11 +27,11 @@ import (
"image/jpeg"
"image/png"
"io"
"os"
"reflect"
"testing"
"github.com/disintegration/imaging"
"golang.org/x/image/bmp"
)
var (
@ -116,7 +119,7 @@ func TestTransform(t *testing.T) {
{"bmp", func(w io.Writer, m image.Image) { bmp.Encode(w, m) }, true},
{"gif", func(w io.Writer, m image.Image) { gif.Encode(w, m, nil) }, true},
{"jpeg", func(w io.Writer, m image.Image) { jpeg.Encode(w, m, nil) }, false},
{"png", func(w io.Writer, m image.Image) { png.Encode(w, m) }, true},
{"png", func(w io.Writer, m image.Image) { png.Encode(w, m) }, false},
}
for _, tt := range tests {
@ -128,7 +131,8 @@ func TestTransform(t *testing.T) {
if err != nil {
t.Errorf("Transform with encoder %s returned unexpected error: %v", tt.name, err)
}
if !reflect.DeepEqual(in, out) {
if tt.exactOutput && !reflect.DeepEqual(in, out) {
t.Errorf("Transform with with encoder %s with empty options returned modified result", tt.name)
}
@ -136,6 +140,7 @@ func TestTransform(t *testing.T) {
if err != nil {
t.Errorf("Transform with encoder %s returned unexpected error: %v", tt.name, err)
}
if len(out) == 0 {
t.Errorf("Transform with encoder %s returned empty bytes", tt.name)
}
@ -380,3 +385,69 @@ func TestTransformImage(t *testing.T) {
}
}
}
func TestTWMChanges(t *testing.T) {
src, err := getTwmTestImage("test-images/unanime.png")
if err != nil {
t.Errorf("test failed getting image: %v", err)
t.Fail()
}
tests := []struct {
name string
matchOutFilename string
options Options
}{
{"jpeg 400x", "test-images/unanime-400x.png", Options{Width: 400}},
{"jpeg 400x,200ml", "test-images/unanime-400x,200ml.png", Options{Width: 400, IndicatorSize: optIndicatorSize200ml, Square: true}},
}
for _, tt := range tests {
shouldOut, err := getTwmTestImage(tt.matchOutFilename)
if err != nil {
t.Errorf("test failed getting out image %s: %v", tt.matchOutFilename, err)
continue
}
out, err := Transform(src, tt.options)
if err != nil {
t.Errorf("Transform with encoder %s returned unexpected error: %v", tt.name, err)
}
if !reflect.DeepEqual(shouldOut, out) {
TMPORARYWriteTestImage("test-images/tmepout.png", out)
t.Errorf("Transform with with encoder %s with empty options returned modified result", tt.name)
}
fmt.Println("done", tt.name)
}
}
func getTwmTestImage(name string) ([]byte, error) {
src, err := os.Open(name)
if err != nil {
return nil, err
}
stat, err := src.Stat()
if err != nil {
return nil, err
}
bs := make([]byte, stat.Size())
bufio.NewReader(src).Read(bs)
return bs, nil
}
func TMPORARYWriteTestImage(name string, bs []byte) {
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
fmt.Println(err)
return
}
n, err := f.Write(bs)
fmt.Println(n, err)
}