package image_test import ( "bytes" "fmt" "io/ioutil" "mime/multipart" "net/http" "net/http/httptest" "net/textproto" "os" "path" "path/filepath" "strings" "testing" "github.com/gomodule/redigo/redis" "github.com/rafaeljusto/redigomock" _ "github.com/stretchr/testify/mock" db "git.ofmax.li/iserv/internal/db/redis" "git.ofmax.li/iserv/internal/image" ) // from go lang src https://golang.org/src/mime/multipart/writer.go // there seems to be no way to set the content type. var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") func escapeQuotes(s string) string { return quoteEscaper.Replace(s) } // end go lang src func createHeader(fieldname, filename, contentType string) textproto.MIMEHeader { h := make(textproto.MIMEHeader) h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, escapeQuotes(fieldname), escapeQuotes(filename))) h.Set("Content-Type", escapeQuotes(contentType)) return h } func prepareRequest(t *testing.T, filename, mimeType string) (*multipart.Writer, *bytes.Buffer, error) { fileDir, _ := os.Getwd() fileName := filename filePath := path.Join(fileDir, fileName) body := &bytes.Buffer{} writer := multipart.NewWriter(body) header := createHeader("file", filePath, mimeType) part, err := writer.CreatePart(header) if err != nil { t.Errorf("wtf %s", err) } file, err := os.Open(filePath) if err != nil { t.Errorf("couldnt open: %s", err) } defer file.Close() fileBytes, err := ioutil.ReadAll(file) if err != nil { t.Errorf("couldn't read buffer: %s", fileBytes) } part.Write(fileBytes) writer.Close() return writer, body, err } func TestImage(t *testing.T) { // setup redis for tests conn := redigomock.NewConn() pool := &redis.Pool{ // Return the same connection mock for each Get() call. Dial: func() (redis.Conn, error) { return conn, nil }, MaxIdle: 10, } conn.Command("HMSET", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()) repo := db.NewRedisImageRepo(pool) // setup image package imageBuildDir, err := ioutil.TempDir("", "test-images") if err != nil { t.Fatal(err) } defer os.RemoveAll(imageBuildDir) imageService := image.NewService(repo, imageBuildDir) imageHandler := image.NewHandler(imageService) handler := http.HandlerFunc(imageHandler.PostImage) // prep test with png writer, body, err := prepareRequest(t, "t.png", "image/png") if err != nil { t.Fatal(err) } w := httptest.NewRecorder() r, err := http.NewRequest("POST", "http://example.com", body) if err != nil { t.Errorf("%s", err) } r.Header.Add("Content-Type", writer.FormDataContentType()) handler.ServeHTTP(w, r) response := w.Result() if response.StatusCode != http.StatusCreated { t.Errorf("image create status 201") } // incorrect mime writer, body, err = prepareRequest(t, "t.pdf", "application/pdf") if err != nil { t.Fatal(err) } w = httptest.NewRecorder() r, err = http.NewRequest("POST", "http://example.com", body) if err != nil { t.Fatal(err) } r.Header.Add("Content-Type", writer.FormDataContentType()) handler.ServeHTTP(w, r) response = w.Result() if response.StatusCode != http.StatusBadRequest { t.Errorf("image create not 400") } // sneaky mimetype check writer, body, err = prepareRequest(t, "t.png", "image/jpeg") if err != nil { t.Fatal(err) } w = httptest.NewRecorder() r, err = http.NewRequest("POST", "http://example.com", body) if err != nil { t.Errorf("%s", err) } r.Header.Add("Content-Type", writer.FormDataContentType()) handler.ServeHTTP(w, r) response = w.Result() if response.StatusCode != http.StatusBadRequest { t.Errorf("image create not 400") } // test image write path && ext // TODO pngs, err := filepath.Glob(filepath.Join(imageBuildDir)) if err != nil { t.Fatal(err) } if len(pngs) != 1 { t.Error("expected only 1 image to be found") } }