imaginary/server_test.go

434 lines
9.2 KiB
Go

package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path"
"strings"
"testing"
"github.com/h2non/bimg"
)
func TestIndex(t *testing.T) {
opts := ServerOptions{PathPrefix: "/"}
ts := testServer(indexController(opts))
defer ts.Close()
res, err := http.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(body), "imaginary") == false {
t.Fatalf("Invalid body response: %s", body)
}
}
func TestCrop(t *testing.T) {
ts := testServer(controller(Crop))
buf := readFile("large.jpg")
url := ts.URL + "?width=300"
defer ts.Close()
res, err := http.Post(url, "image/jpeg", buf)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
if res.Header.Get("Content-Length") == "" {
t.Fatal("Empty content length response")
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 300, 1080)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestResize(t *testing.T) {
ts := testServer(controller(Resize))
buf := readFile("large.jpg")
url := ts.URL + "?width=300&nocrop=false"
defer ts.Close()
res, err := http.Post(url, "image/jpeg", buf)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 300, 1080)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestEnlarge(t *testing.T) {
ts := testServer(controller(Enlarge))
buf := readFile("large.jpg")
url := ts.URL + "?width=300&height=200"
defer ts.Close()
res, err := http.Post(url, "image/jpeg", buf)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 300, 200)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestExtract(t *testing.T) {
ts := testServer(controller(Extract))
buf := readFile("large.jpg")
url := ts.URL + "?top=100&left=100&areawidth=200&areaheight=120"
defer ts.Close()
res, err := http.Post(url, "image/jpeg", buf)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 200, 120)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestTypeAuto(t *testing.T) {
cases := []struct {
acceptHeader string
expected string
}{
{"", "jpeg"},
{"image/webp,*/*", "webp"},
{"image/png,*/*", "png"},
{"image/webp;q=0.8,image/jpeg", "webp"},
{"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "webp"}, // Chrome
}
for _, test := range cases {
ts := testServer(controller(Crop))
buf := readFile("large.jpg")
url := ts.URL + "?width=300&type=auto"
defer ts.Close()
req, _ := http.NewRequest(http.MethodPost, url, buf)
req.Header.Add("Content-Type", "image/jpeg")
req.Header.Add("Accept", test.acceptHeader)
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
if res.Header.Get("Content-Length") == "" {
t.Fatal("Empty content length response")
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 300, 1080)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != test.expected {
t.Fatalf("Invalid image type")
}
if res.Header.Get("Vary") != "Accept" {
t.Fatal("Vary header not set correctly")
}
}
}
func TestFit(t *testing.T) {
var err error
buf := readFile("large.jpg")
original, _ := ioutil.ReadAll(buf)
err = assertSize(original, 1920, 1080)
if err != nil {
t.Errorf("Reference image expecations weren't met")
}
ts := testServer(controller(Fit))
url := ts.URL + "?width=300&height=300"
defer ts.Close()
res, err := http.Post(url, "image/jpeg", bytes.NewReader(original))
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %s", res.Status)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
// The reference image has a ratio of 1.778, this should produce a height of 168.75
err = assertSize(image, 300, 169)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestRemoteHTTPSource(t *testing.T) {
opts := ServerOptions{EnableURLSource: true}
fn := ImageMiddleware(opts)(Crop)
LoadSources(opts)
tsImage := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
buf, _ := ioutil.ReadFile("testdata/large.jpg")
_, _ = w.Write(buf)
}))
defer tsImage.Close()
ts := httptest.NewServer(fn)
url := ts.URL + "?width=200&height=200&url=" + tsImage.URL
defer ts.Close()
res, err := http.Get(url)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %d", res.StatusCode)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 200, 200)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestInvalidRemoteHTTPSource(t *testing.T) {
opts := ServerOptions{EnableURLSource: true}
fn := ImageMiddleware(opts)(Crop)
LoadSources(opts)
tsImage := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(400)
}))
defer tsImage.Close()
ts := httptest.NewServer(fn)
url := ts.URL + "?width=200&height=200&url=" + tsImage.URL
defer ts.Close()
res, err := http.Get(url)
if err != nil {
t.Fatal("Request failed")
}
if res.StatusCode != 400 {
t.Fatalf("Invalid response status: %d", res.StatusCode)
}
}
func TestMountDirectory(t *testing.T) {
opts := ServerOptions{Mount: "testdata"}
fn := ImageMiddleware(opts)(Crop)
LoadSources(opts)
ts := httptest.NewServer(fn)
url := ts.URL + "?width=200&height=200&file=large.jpg"
defer ts.Close()
res, err := http.Get(url)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 200 {
t.Fatalf("Invalid response status: %d", res.StatusCode)
}
image, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(image) == 0 {
t.Fatalf("Empty response body")
}
err = assertSize(image, 200, 200)
if err != nil {
t.Error(err)
}
if bimg.DetermineImageTypeName(image) != "jpeg" {
t.Fatalf("Invalid image type")
}
}
func TestMountInvalidDirectory(t *testing.T) {
fn := ImageMiddleware(ServerOptions{Mount: "_invalid_"})(Crop)
ts := httptest.NewServer(fn)
url := ts.URL + "?top=100&left=100&areawidth=200&areaheight=120&file=large.jpg"
defer ts.Close()
res, err := http.Get(url)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 400 {
t.Fatalf("Invalid response status: %d", res.StatusCode)
}
}
func TestMountInvalidPath(t *testing.T) {
fn := ImageMiddleware(ServerOptions{Mount: "_invalid_"})(Crop)
ts := httptest.NewServer(fn)
url := ts.URL + "?top=100&left=100&areawidth=200&areaheight=120&file=../../large.jpg"
defer ts.Close()
res, err := http.Get(url)
if err != nil {
t.Fatal("Cannot perform the request")
}
if res.StatusCode != 400 {
t.Fatalf("Invalid response status: %s", res.Status)
}
}
func controller(op Operation) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
buf, _ := ioutil.ReadAll(r.Body)
imageHandler(w, r, buf, op, ServerOptions{})
}
}
func testServer(fn func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(fn))
}
func readFile(file string) io.Reader {
buf, _ := os.Open(path.Join("testdata", file))
return buf
}
func assertSize(buf []byte, width, height int) error {
size, err := bimg.NewImage(buf).Size()
if err != nil {
return err
}
if size.Width != width || size.Height != height {
return fmt.Errorf("invalid image size: %dx%d, expected: %dx%d", size.Width, size.Height, width, height)
}
return nil
}