diff --git a/.travis.yml b/.travis.yml index 862a283..e484277 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,20 +2,28 @@ language: go go: - 1.13 - + +env: GO111MODULE=on arch: - amd64 - arm64 - os: - windows - osx - linux -env: GO111MODULE=on +script: sh scripts/build.sh $TRAVIS_OS_NAME $TRAVIS_CPU_ARCH -script: - - sh scripts/build.sh $TRAVIS_OS_NAME $TRAVIS_CPU_ARCH +jobs: + include: + - stage: "Unit Tests" + arch: + - amd64 + os: + - linux + script: + - go test -v -cover encoder_test.go encoder.go helper.go + - go test -v -cover helper_test.go helper.go deploy: provider: releases diff --git a/encoder_test.go b/encoder_test.go new file mode 100644 index 0000000..848e5f3 --- /dev/null +++ b/encoder_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +//go test -v -cover encoder_test.go encoder.go helper.go +func TestWebpEncoder(t *testing.T) { + + var webp = "/tmp/test-result.webp" + var target = walker() + + for _, f := range target { + //fmt.Println(b, c, webp) + runEncoder(t, f, webp) + } + _ = os.Remove(webp) + +} + +func walker() []string { + var list []string + _ = filepath.Walk("./pics", func(path string, info os.FileInfo, err error) error { + if !info.IsDir() { + list = append(list, path) + } + return nil + }) + return list +} + +func runEncoder(t *testing.T, file string, webp string) { + var c chan int + //t.Logf("Convert from %s to %s", file, webp) + var err = WebpEncoder(file, webp, 80, false, c) + if file == "pics/empty.jpg" && err != nil { + t.Log("Empty file, that's okay.") + } else if err != nil { + t.Fatalf("Fatal, convert failed for %s: %v ", file, err) + } + + data, _ := ioutil.ReadFile(webp) + types := GetFileContentType(data[:512]) + if types != "image/webp" { + t.Fatal("Fatal, file type is wrong!") + } + +} diff --git a/helper.go b/helper.go index 324bab8..5e63526 100644 --- a/helper.go +++ b/helper.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "github.com/gofiber/fiber" log "github.com/sirupsen/logrus" "net/http" "os" @@ -62,34 +61,8 @@ func GenWebpAbs(RawImagePath string, ExhaustPath string, ImgFilename string, req return cwd, WebpAbsolutePath } -func CheckUA(c *fiber.Ctx, RawImageAbs string) (string, bool) { - // reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox - // https://developer.chrome.com/multidevice/user-agent#chrome_for_ios_user_agent - // Chrome - // ✅ Windows: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 - // ✅ macOS: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 - // ✅ Linux: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 - // ✅ iOS: Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/83.0.4103.63 Mobile/15E148 Safari/604.1 - // ✅ Android: Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.60 Mobile Safari/537.36 - - // Firefox - // ✅ Windows: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0 - // ✅ macOS: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0 - // ✅ Linux: Mozilla/5.0 (X11; Linux i686; rv:76.0) Gecko/20100101 Firefox/76.0 - // ✅ iOS: Mozilla/5.0 (iPad; CPU OS 10_15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/25.0 Mobile/15E148 Safari/605.1.15 - // ✅ Android: Mozilla/5.0 (Android 10; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0 - - // Safari - // ❎ macOS: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15 - // ❎ iOS: Mozilla/5.0 (iPad; CPU OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1 - - // WeChat - // ❎ iOS: Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60 wxwork/2.1.5 MicroMessenger/6.3.22 - // ✅ Windows: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.691.400 QQBrowser/9.0.2524.400 - // ✅ Android: Mozilla/5.0 (Linux; Android 7.0; LG-H831 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36 MicroMessenger/6.6.7.1303(0x26060743) NetType/WIFI Language/zh_TW - - UA := c.Get("User-Agent") - +func isSafari(UA string) bool { + // for more information, please check test case if strings.Contains(UA, "Firefox") || strings.Contains(UA, "Chrome") { // Chrome or firefox on macOS Windows } else if strings.Contains(UA, "Android") || strings.Contains(UA, "Windows") || strings.Contains(UA, "Linux") { @@ -97,9 +70,7 @@ func CheckUA(c *fiber.Ctx, RawImageAbs string) (string, bool) { } else if strings.Contains(UA, "FxiOS") || strings.Contains(UA, "CriOS") { //firefox and Chrome on iOS } else { - log.Infof("A Safari user has arrived...%s", UA) - c.SendFile(RawImageAbs) - return "", true + return true } - return UA, false + return false } diff --git a/helper_test.go b/helper_test.go new file mode 100644 index 0000000..33b2170 --- /dev/null +++ b/helper_test.go @@ -0,0 +1,97 @@ +package main + +import ( + "strings" + "testing" +) + +// test this file: go test -v -cover helper_test.go helper.go +// test one function: go test -run TestGetFileContentType helper_test.go helper.go -v +func TestGetFileContentType(t *testing.T) { + var data = []byte("hello") + var expected = "text/plain; charset=utf-8" + var result = GetFileContentType(data) + + if result != expected { + t.Errorf("Result: [%s], Expected: [%s]", result, expected) + } + +} + +// TODO: make a universal logging function +func TestFileCount(t *testing.T) { + var data = ".github" + var expected = 2 + var result = FileCount(data) + + if result != expected { + t.Errorf("Result: [%d], Expected: [%d]", result, expected) + } +} + +func TestImageExists(t *testing.T) { + var data = "./pics/empty.jpg" + var result = !ImageExists(data) + + if result { + t.Errorf("Result: [%v], Expected: [%v]", result, false) + } + data = ".pics/empty2.jpg" + result = ImageExists(data) + + if result { + t.Errorf("Result: [%v], Expected: [%v]", result, false) + } + +} + +func TestGenWebpAbs(t *testing.T) { + cwd, cooked := GenWebpAbs("./pics/webp_server.png", "/tmp", + "test", "a") + if !strings.Contains(cwd, "webp_server_go") { + t.Logf("Result: [%v], Expected: [%v]", cwd, "webp_server_go") + } + var parts = strings.Split(cooked, ".") + if parts[0] != "/tmp/test" || parts[2] != "webp" { + t.Errorf("Result: [%v], Expected: [%v]", cooked, "/tmp/test..webp") + + } +} + +func TestisSafari(t *testing.T) { + // reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox + // https://developer.chrome.com/multidevice/user-agent#chrome_for_ios_user_agent + + var testCase = map[string]bool{ + // Chrome on Windows, macOS, linux, iOS and Android + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36": false, + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36": false, + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36": false, + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/83.0.4103.63 Mobile/15E148 Safari/604.1": false, + "Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.60 Mobile Safari/537.36": false, + + // Firefox on Windows, macOS, linux, iOS and Android + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0": false, + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0": false, + "Mozilla/5.0 (X11; Linux i686; rv:76.0) Gecko/20100101 Firefox/76.0": false, + "Mozilla/5.0 (iPad; CPU OS 10_15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/25.0 Mobile/15E148 Safari/605.1.15": false, + "Mozilla/5.0 (Android 10; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0": false, + + // Safari on macOS and iOS + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15": true, + "Mozilla/5.0 (iPad; CPU OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1": true, + + // WeChat on iOS, Windows, and Android + "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60 wxwork/2.1.5 MicroMessenger/6.3.22": true, + "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.691.400 QQBrowser/9.0.2524.400": false, + "Mozilla/5.0 (Linux; Android 7.0; LG-H831 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36 MicroMessenger/6.6.7.1303(0x26060743) NetType/WIFI Language/zh_TW": false, + } + + for browser, is := range testCase { + + if is != isSafari(browser) { + t.Errorf("[%v]:[%s]", is, browser) + } + } + +} diff --git a/router.go b/router.go index a99f1b1..abeda26 100644 --- a/router.go +++ b/router.go @@ -19,9 +19,11 @@ func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY var RawImageAbs = path.Join(ImgPath, reqURI) // /home/xxx/mypic/123.jpg var ImgFilename = path.Base(reqURI) // pure filename, 123.jpg var finalFile string // We'll only need one c.sendFile() - - UA, done := CheckUA(c, RawImageAbs) + var UA = c.Get("User-Agent") + done := isSafari(UA) if done { + log.Infof("A Safari user has arrived...%s", UA) + c.SendFile(RawImageAbs) return } log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), ImgFilename) diff --git a/scripts/unit_test.sh b/scripts/unit_test.sh new file mode 100644 index 0000000..2900710 --- /dev/null +++ b/scripts/unit_test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# bash scripts/unit_test.sh +# check $? for success or failure +go test -v -cover encoder_test.go encoder.go helper.go +go test -v -cover helper_test.go helper.go + +# if [[ $? -ne 0 ]] ; then +# echo "TEST FAILED!!! PLEASE DOUBLE CHECK." +# fi diff --git a/update.go b/update.go index e897d65..033b292 100644 --- a/update.go +++ b/update.go @@ -15,7 +15,7 @@ import ( func autoUpdate() { defer func() { if err := recover(); err != nil { - log.Errorf("Download error.", err) + log.Errorf("Download error: %s", err) } }() @@ -45,7 +45,7 @@ func autoUpdate() { log.Info("Downloading binary to update...") resp, _ := http.Get(releaseUrl) if resp.StatusCode != 200 { - log.Debug("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH) + log.Debugf("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH) return } data, _ := ioutil.ReadAll(resp.Body) diff --git a/webp-server.go b/webp-server.go index 46125e5..a56bee5 100644 --- a/webp-server.go +++ b/webp-server.go @@ -21,7 +21,7 @@ type Config struct { ExhaustPath string `json:"EXHAUST_PATH"` } -const version = "0.1.2" +const version = "0.1.3" var configPath string var prefetch bool