diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 24c51f6..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: n0vad3v - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots and logs** -If applicable, add screenshots and logs to help explain your problem. - -**Environment (please complete the following information):** - - OS: [e.g. Linux] - - version or branch[e.g. 0.0.3, master] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 3f41544..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: n0vad3v - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/release_docker_image.yaml b/.github/workflows/release_docker_image.yaml index 098496a..a48c399 100644 --- a/.github/workflows/release_docker_image.yaml +++ b/.github/workflows/release_docker_image.yaml @@ -1,4 +1,5 @@ -name: Build docker images +name: Build and Push Docker Image + on: push: paths-ignore: @@ -16,9 +17,27 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout + - name: Checkout code uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.23' + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libvips-dev + + - name: Build for amd64 + run: | + GOOS=linux GOARCH=amd64 go build -o builds/webp-server-linux-amd64 . + + - name: Build for arm64 + run: | + GOOS=linux GOARCH=arm64 go build -o builds/webp-server-linux-arm64 . + - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -31,11 +50,12 @@ jobs: username: woodchen password: ${{ secrets.ACCESS_TOKEN }} - - name: Build and push + - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . - file: Dockerfile + file: Dockerfile.multi push: true tags: woodchen/${{ env.IMAGE_NAME }}:latest platforms: linux/amd64,linux/arm64 + diff --git a/Dockerfile.multi b/Dockerfile.multi new file mode 100644 index 0000000..efe677d --- /dev/null +++ b/Dockerfile.multi @@ -0,0 +1,18 @@ +FROM debian:bookworm-slim + +RUN apt-get update && \ + apt-get install --no-install-recommends -y libvips ca-certificates libjemalloc2 libtcmalloc-minimal4 && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /var/cache/apt/archives/* + +WORKDIR /usr/bin +COPY builds/webp-server-linux-amd64 webp-server-linux-amd64 +COPY builds/webp-server-linux-arm64 webp-server-linux-arm64 +COPY config.json /etc/config.json + +RUN chmod +x webp-server-linux-amd64 webp-server-linux-arm64 + +WORKDIR /opt +VOLUME /opt/exhaust + +CMD ["/bin/sh", "-c", "if [ \"$(uname -m)\" = \"aarch64\" ]; then /usr/bin/webp-server-linux-arm64 --config /etc/config.json; else /usr/bin/webp-server-linux-amd64 --config /etc/config.json; fi"] diff --git a/Makefile b/Makefile index 9b11f50..3bbd811 100644 --- a/Makefile +++ b/Makefile @@ -33,11 +33,8 @@ static-check: install-staticcheck tools/bin/staticcheck -checks all,-ST1000 ./... GO111MODULE=on tools/bin/golangci-lint run -v $$($(PACKAGE_DIRECTORIES)) --config .golangci.yml -test: - go test -v -coverprofile=coverage.txt -covermode=atomic ./... - clean: - rm -rf prefetch remote-raw exhaust tools coverage.txt metadata exhaust_test + rm -rf prefetch remote-raw exhaust tools metadata exhaust_test docker: DOCKER_BUILDKIT=1 docker build -t webpsh/webps . diff --git a/config/config_test.go b/config/config_test.go deleted file mode 100644 index 9ef0016..0000000 --- a/config/config_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestMain(m *testing.M) { - ConfigPath = "../config.json" - m.Run() - ConfigPath = "config.json" - Config.ImgPath = "./pics" -} - -func TestLoadConfig(t *testing.T) { - LoadConfig() - assert.Equal(t, Config.Host, "127.0.0.1") - assert.Equal(t, Config.Port, "3333") - assert.Equal(t, Config.Quality, 80) - assert.Equal(t, Config.ImgPath, "./pics") - assert.Equal(t, Config.ImageMap, map[string]string{}) - assert.Equal(t, Config.ExhaustPath, "./exhaust") - assert.Equal(t, Config.CacheTTL, 259200) - assert.Equal(t, Config.MaxCacheSize, 0) -} - -func TestSwitchProxyMode(t *testing.T) { - switchProxyMode() - assert.False(t, ProxyMode) - Config.ImgPath = "https://picsum.photos" - switchProxyMode() - assert.True(t, ProxyMode) -} - -func TestParseImgMap(t *testing.T) { - empty := map[string]string{} - good := map[string]string{ - "/1": "../pics/dir1", - "http://example.com": "../pics", - "https://example.com": "../pics", - } - bad := map[string]string{ - "1": "../pics/dir1", - "httpx://example.com": "../pics", - "ftp://example.com": "../pics", - } - - assert.Equal(t, empty, parseImgMap(empty)) - assert.Equal(t, empty, parseImgMap(bad)) - assert.Equal(t, good, parseImgMap(good)) - - for k, v := range good { - bad[k] = v - } - assert.Equal(t, good, parseImgMap(bad)) -} diff --git a/encoder/process_test.go b/encoder/process_test.go deleted file mode 100644 index 82ed925..0000000 --- a/encoder/process_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package encoder - -import ( - "testing" - "webp_server_go/config" - - "github.com/davidbyttow/govips/v2/vips" -) - -func TestResizeImage(t *testing.T) { - img, _ := vips.Black(500, 500) - - // Define the parameters for the test cases - testCases := []struct { - extraParams config.ExtraParams // Extra parameters - expectedH int // Expected height - expectedW int // Expected width - }{ - // Tests for MaxHeight and MaxWidth - // Both extraParams.MaxHeight and extraParams.MaxWidth are 0 - { - extraParams: config.ExtraParams{ - MaxHeight: 0, - MaxWidth: 0, - }, - expectedH: 500, - expectedW: 500, - }, - // Both extraParams.MaxHeight and extraParams.MaxWidth are greater than 0, but the image size is smaller than the limits - { - extraParams: config.ExtraParams{ - MaxHeight: 1000, - MaxWidth: 1000, - }, - expectedH: 500, - expectedW: 500, - }, - // Both extraParams.MaxHeight and extraParams.MaxWidth are greater than 0, and the image exceeds the limits - { - extraParams: config.ExtraParams{ - MaxHeight: 200, - MaxWidth: 200, - }, - expectedH: 200, - expectedW: 200, - }, - // Only MaxHeight is set to 200 - { - extraParams: config.ExtraParams{ - MaxHeight: 200, - MaxWidth: 0, - }, - expectedH: 200, - expectedW: 200, - }, - - // Test for Width and Height - { - extraParams: config.ExtraParams{ - Width: 200, - Height: 200, - }, - expectedH: 200, - expectedW: 200, - }, - { - extraParams: config.ExtraParams{ - Width: 200, - Height: 500, - }, - expectedH: 500, - expectedW: 200, - }, - } - - // Iterate through the test cases and perform the tests - for _, tc := range testCases { - err := resizeImage(img, tc.extraParams) - if err != nil { - t.Errorf("resizeImage failed with error: %v", err) - } - - // Verify if the adjusted image height and width match the expected values - actualH := img.Height() - actualW := img.Width() - if actualH != tc.expectedH || actualW != tc.expectedW { - t.Errorf("resizeImage failed: expected (%d, %d), got (%d, %d)", tc.expectedH, tc.expectedW, actualH, actualW) - } - } -} diff --git a/encoder/rawconvert_test.go b/encoder/rawconvert_test.go deleted file mode 100644 index 33277db..0000000 --- a/encoder/rawconvert_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package encoder - -import ( - "testing" -) - -func TestConvertRawToJPG(t *testing.T) { - testCases := []struct { - rawPath string - optimizedPath string - expectedResult string - expectedStatus bool - }{ - // blackbird.NEF is from https://github.com/jewright/nef-to-jpg/blob/main/photoconverter/Sample-Images/blackbird.NEF - {"../pics/blackbird.NEF", "../exhaust_test/", "../exhaust_test/blackbird.NEF_extracted.jpg", true}, - {"../pics/big.jpg", "../exhaust_test/", "../pics/big.jpg", false}, - } - - for _, tc := range testCases { - result, status := ConvertRawToJPG(tc.rawPath, tc.optimizedPath) - - if result != tc.expectedResult || status != tc.expectedStatus { - t.Errorf("ConvertRawToJPG(%s, %s) => (%s, %t), expected (%s, %t)", tc.rawPath, tc.optimizedPath, result, status, tc.expectedResult, tc.expectedStatus) - } - } -} diff --git a/handler/router_test.go b/handler/router_test.go deleted file mode 100644 index 94b296b..0000000 --- a/handler/router_test.go +++ /dev/null @@ -1,347 +0,0 @@ -package handler - -import ( - "io" - "net/http" - "net/http/httptest" - "net/url" - "os" - "testing" - "time" - "webp_server_go/config" - "webp_server_go/helper" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/etag" - "github.com/patrickmn/go-cache" - "github.com/stretchr/testify/assert" -) - -var ( - chromeUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36" - safariUA = "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" - safari17UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Safari/605.1.15" // <- Mac with Safari 17 - curlUA = "curl/7.64.1" - - acceptWebP = "image/webp,image/apng,image/*,*/*;q=0.8" - acceptAvif = "image/avif,image/*,*/*;q=0.8" - acceptLegacy = "image/jpeg,image/png" -) - -func setupParam() { - // setup parameters here... - config.Config.ImgPath = "../pics" - config.Config.ExhaustPath = "../exhaust_test" - config.Config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"} - config.Config.MetadataPath = "../metadata" - config.Config.RemoteRawPath = "../remote-raw" - config.ProxyMode = false - config.Config.EnableWebP = true - config.Config.EnableAVIF = false - config.Config.Quality = 80 - config.Config.ImageMap = map[string]string{} - config.RemoteCache = cache.New(cache.NoExpiration, 10*time.Minute) -} - -func requestToServer(reqUrl string, app *fiber.App, ua, accept string) (*http.Response, []byte) { - parsedUrl, _ := url.Parse(reqUrl) - req := httptest.NewRequest("GET", parsedUrl.EscapedPath(), nil) - req.Header.Set("User-Agent", ua) - req.Header.Set("Accept", accept) - req.Header.Set("Host", parsedUrl.Host) - req.Host = parsedUrl.Host - resp, err := app.Test(req, 120000) - if err != nil { - return nil, nil - } - data, _ := io.ReadAll(resp.Body) - return resp, data -} - -func TestServerHeaders(t *testing.T) { - setupParam() - var app = fiber.New() - app.Use(etag.New(etag.Config{ - Weak: true, - })) - app.Get("/*", Convert) - url := "http://127.0.0.1:3333/webp_server.bmp" - - // test for chrome - response, _ := requestToServer(url, app, chromeUA, acceptWebP) - defer response.Body.Close() - ratio := response.Header.Get("X-Compression-Rate") - etag := response.Header.Get("Etag") - - assert.NotEqual(t, "", ratio) - assert.NotEqual(t, "", etag) - - // test for safari - response, _ = requestToServer(url, app, safariUA, acceptLegacy) - defer response.Body.Close() - // ratio = response.Header.Get("X-Compression-Rate") - etag = response.Header.Get("Etag") - - assert.NotEqual(t, "", etag) -} - -func TestConvertDuplicates(t *testing.T) { - setupParam() - N := 3 - - var testLink = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/webp", - "http://127.0.0.1:3333/webp_server.bmp": "image/webp", - "http://127.0.0.1:3333/webp_server.png": "image/webp", - "http://127.0.0.1:3333/empty.jpg": "", - "http://127.0.0.1:3333/png.jpg": "image/webp", - "http://127.0.0.1:3333/12314.jpg": "", - "http://127.0.0.1:3333/dir1/inside.jpg": "image/webp", - "http://127.0.0.1:3333/%e5%a4%aa%e7%a5%9e%e5%95%a6.png": "image/webp", - "http://127.0.0.1:3333/太神啦.png": "image/webp", - } - - var app = fiber.New() - app.Get("/*", Convert) - - // test Chrome - for url, respType := range testLink { - for range N { - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - contentType := helper.GetContentType(data) - assert.Equal(t, respType, contentType) - } - } - -} -func TestConvert(t *testing.T) { - setupParam() - // TODO: old-style test, better update it with accept headers - var testChromeLink = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/webp", - "http://127.0.0.1:3333/webp_server.bmp": "image/webp", - "http://127.0.0.1:3333/webp_server.png": "image/webp", - "http://127.0.0.1:3333/empty.jpg": "", - "http://127.0.0.1:3333/png.jpg": "image/webp", - "http://127.0.0.1:3333/12314.jpg": "", - "http://127.0.0.1:3333/dir1/inside.jpg": "image/webp", - "http://127.0.0.1:3333/%e5%a4%aa%e7%a5%9e%e5%95%a6.png": "image/webp", - "http://127.0.0.1:3333/太神啦.png": "image/webp", - } - - var testChromeAvifLink = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/avif", - "http://127.0.0.1:3333/webp_server.bmp": "image/avif", - "http://127.0.0.1:3333/webp_server.png": "image/avif", - "http://127.0.0.1:3333/empty.jpg": "", - "http://127.0.0.1:3333/png.jpg": "image/avif", - "http://127.0.0.1:3333/12314.jpg": "", - "http://127.0.0.1:3333/dir1/inside.jpg": "image/avif", - "http://127.0.0.1:3333/%e5%a4%aa%e7%a5%9e%e5%95%a6.png": "image/avif", - "http://127.0.0.1:3333/太神啦.png": "image/avif", - } - - var testSafariLink = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/jpeg", - "http://127.0.0.1:3333/webp_server.bmp": "image/png", // png instead oft bmp because ResizeItself() uses ExportNative() - "http://127.0.0.1:3333/webp_server.png": "image/png", - "http://127.0.0.1:3333/empty.jpg": "", - "http://127.0.0.1:3333/png.jpg": "image/png", - "http://127.0.0.1:3333/12314.jpg": "", - "http://127.0.0.1:3333/dir1/inside.jpg": "image/jpeg", - } - - var app = fiber.New() - app.Get("/*", Convert) - - // // test Chrome - for url, respType := range testChromeLink { - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - contentType := helper.GetContentType(data) - assert.Equal(t, respType, contentType) - } - - // test Safari - for url, respType := range testSafariLink { - resp, data := requestToServer(url, app, safariUA, acceptLegacy) - defer resp.Body.Close() - contentType := helper.GetContentType(data) - assert.Equal(t, respType, contentType) - } - - // test Avif is processed in proxy mode - config.Config.EnableAVIF = true - for url, respType := range testChromeAvifLink { - resp, data := requestToServer(url, app, chromeUA, acceptAvif) - defer resp.Body.Close() - contentType := helper.GetContentType(data) - assert.NotNil(t, respType) - assert.Equal(t, respType, contentType) - } -} - -func TestConvertNotAllowed(t *testing.T) { - setupParam() - config.Config.AllowedTypes = []string{"jpg", "png", "jpeg"} - - var app = fiber.New() - app.Get("/*", Convert) - - // not allowed, but we have the file, this should return File extension not allowed - url := "http://127.0.0.1:3333/webp_server.bmp" - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Contains(t, string(data), "File extension not allowed") - - // not allowed, random file - url = url + "hagdgd" - resp, data = requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Contains(t, string(data), "File extension not allowed") - -} - -func TestConvertProxyModeBad(t *testing.T) { - setupParam() - config.ProxyMode = true - - var app = fiber.New() - app.Get("/*", Convert) - - // this is local random image, should be 404 - url := "http://127.0.0.1:3333/webp_8888server.bmp" - resp, _ := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Equal(t, http.StatusNotFound, resp.StatusCode) - - // this is local random image, test using cURL, should be 404, ref: https://github.com/webp-sh/webp_server_go/issues/197 - resp1, _ := requestToServer(url, app, curlUA, acceptWebP) - defer resp1.Body.Close() - assert.Equal(t, http.StatusNotFound, resp1.StatusCode) - -} - -func TestConvertProxyModeWork(t *testing.T) { - setupParam() - config.ProxyMode = true - config.Config.ImgPath = "https://docs.webp.sh" - - var app = fiber.New() - app.Get("/*", Convert) - - url := "http://127.0.0.1:3333/images/webp_server.jpg" - - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Equal(t, "image/webp", helper.GetContentType(data)) - - // test proxyMode with Safari - resp, data = requestToServer(url, app, safariUA, acceptLegacy) - defer resp.Body.Close() - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Equal(t, "image/jpeg", helper.GetContentType(data)) -} - -func TestConvertProxyImgMap(t *testing.T) { - setupParam() - config.ProxyMode = false - config.Config.ImageMap = map[string]string{ - "/2": "../pics/dir1", - "/3": "../pics3", // Invalid path, does not exists - "www.invalid-path.com": "https://docs.webp.sh", // Invalid, it does not start with '/' - "/www.weird-path.com": "https://docs.webp.sh", - "/www.even-more-werid-path.com": "https://docs.webp.sh/images", - "http://example.com": "https://docs.webp.sh", - } - - var app = fiber.New() - app.Get("/*", Convert) - - var testUrls = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/webp", - "http://127.0.0.1:3333/2/inside.jpg": "image/webp", - "http://127.0.0.1:3333/www.weird-path.com/images/webp_server.jpg": "image/webp", - "http://127.0.0.1:3333/www.even-more-werid-path.com/webp_server.jpg": "image/webp", - "http://example.com//images/webp_server.jpg": "image/webp", - } - - var testUrlsLegacy = map[string]string{ - "http://127.0.0.1:3333/webp_server.jpg": "image/jpeg", - "http://127.0.0.1:3333/2/inside.jpg": "image/jpeg", - "http://example.com/images/webp_server.jpg": "image/jpeg", - } - - var testUrlsInvalid = map[string]string{ - "http://127.0.0.1:3333/3/does-not-exist.jpg": "", // Dir mapped does not exist - "http://127.0.0.1:3333/www.weird-path.com/cover.jpg": "", // Host mapped, final URI invalid - } - - for url, respType := range testUrls { - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Equal(t, respType, helper.GetContentType(data)) - } - - // tests with Safari - for url, respType := range testUrlsLegacy { - resp, data := requestToServer(url, app, safariUA, acceptLegacy) - defer resp.Body.Close() - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Equal(t, respType, helper.GetContentType(data)) - } - - for url, respType := range testUrlsInvalid { - resp, data := requestToServer(url, app, safariUA, acceptLegacy) - defer resp.Body.Close() - assert.Equal(t, http.StatusNotFound, resp.StatusCode) - assert.Equal(t, respType, helper.GetContentType(data)) - } -} - -func TestConvertProxyImgMapCWD(t *testing.T) { - setupParam() - config.ProxyMode = false - config.Config.ImgPath = ".." // equivalent to "" when not testing - config.Config.ImageMap = map[string]string{ - "/1": "../pics/dir1", - "/2": "../pics", - "/3": "../pics", // Invalid path, does not exists - "http://www.example.com": "https://docs.webp.sh", - } - - var app = fiber.New() - app.Get("/*", Convert) - - var testUrls = map[string]string{ - "http://127.0.0.1:3333/1/inside.jpg": "image/webp", - "http://127.0.0.1:3333/2/webp_server.jpg": "image/webp", - "http://127.0.0.1:3333/3/webp_server.jpg": "image/webp", - "http://www.example.com/images/webp_server.jpg": "image/webp", - } - - for url, respType := range testUrls { - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Equal(t, respType, helper.GetContentType(data)) - } -} - -func TestConvertBigger(t *testing.T) { - setupParam() - config.Config.Quality = 100 - - var app = fiber.New() - app.Get("/*", Convert) - - url := "http://127.0.0.1:3333/big.jpg" - resp, data := requestToServer(url, app, chromeUA, acceptWebP) - defer resp.Body.Close() - assert.Equal(t, "image/jpeg", resp.Header.Get("content-type")) - assert.Equal(t, "image/jpeg", helper.GetContentType(data)) - _ = os.RemoveAll(config.Config.ExhaustPath) -} diff --git a/helper/helper_test.go b/helper/helper_test.go deleted file mode 100644 index 645291d..0000000 --- a/helper/helper_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package helper - -import ( - "testing" - "webp_server_go/config" - - "github.com/stretchr/testify/assert" - "github.com/valyala/fasthttp" -) - -func TestMain(m *testing.M) { - config.ConfigPath = "../config.json" - config.LoadConfig() - m.Run() - config.ConfigPath = "config.json" -} - -func TestFileCount(t *testing.T) { - // test helper dir - count := FileCount("./") - assert.Equal(t, int64(4), count) -} - -func TestImageExists(t *testing.T) { - t.Run("file not exists", func(t *testing.T) { - assert.False(t, ImageExists("dgyuaikdsa")) - }) - - // TODO: how to test lock? - - t.Run("test dir", func(t *testing.T) { - assert.False(t, ImageExists("/tmp")) - }) - - t.Run("test file", func(t *testing.T) { - assert.True(t, ImageExists("./helper_test.go")) - }) -} - -func TestCheckAllowedType(t *testing.T) { - t.Run("not allowed type", func(t *testing.T) { - assert.False(t, CheckAllowedType("./helper_test.go")) - }) - - t.Run("allowed type", func(t *testing.T) { - assert.True(t, CheckAllowedType("test.jpg")) - }) -} - -func TestGuessSupportedFormat(t *testing.T) { - tests := []struct { - name string - userAgent string - accept string - expected map[string]bool - }{ - { - name: "WebP/AVIF/JXL Supported", - userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15", // iPad - accept: "image/webp, image/avif", - expected: map[string]bool{ - "raw": true, - "webp": true, - "avif": true, - "jxl": true, - }, - }, - { - name: "WebP/AVIF Supported", - userAgent: "iPhone OS 16", - accept: "image/webp, image/png", - expected: map[string]bool{ - "raw": true, - "webp": true, - "avif": true, - "jxl": false, - }, - }, - { - name: "Both Supported", - userAgent: "iPhone OS 16", - accept: "image/webp, image/avif", - expected: map[string]bool{"raw": true, "webp": true, "avif": true, "jxl": false}, - }, - { - name: "No Supported Formats", - userAgent: "Unknown OS", - accept: "image/jpeg, image/gif", - expected: map[string]bool{"raw": true, "webp": false, "avif": false, "jxl": false}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - header := &fasthttp.RequestHeader{} - header.Set("user-agent", test.userAgent) - header.Set("accept", test.accept) - - result := GuessSupportedFormat(header) - - if len(result) != len(test.expected) { - t.Errorf("Expected %v, but got %v", test.expected, result) - } - - for k, v := range test.expected { - assert.Equal(t, v, result[k]) - } - }) - } -} diff --git a/helper/metadata_test.go b/helper/metadata_test.go deleted file mode 100644 index 1f0015b..0000000 --- a/helper/metadata_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package helper - -import ( - "net/url" - "path" - "testing" - "webp_server_go/config" -) - -func TestGetId(t *testing.T) { - p := "https://example.com/image.jpg?width=200&height=300" - - t.Run("proxy mode", func(t *testing.T) { - // Test case 1: Proxy mode - config.ProxyMode = true - id, jointPath, santizedPath := getId(p) - - // Verify the return values - expectedId := HashString(p) - expectedPath := "" - expectedSantizedPath := "" - if id != expectedId || jointPath != expectedPath || santizedPath != expectedSantizedPath { - t.Errorf("Test case 1 failed: Expected (%s, %s, %s), but got (%s, %s, %s)", - expectedId, expectedPath, expectedSantizedPath, id, jointPath, santizedPath) - } - }) - t.Run("non-proxy mode", func(t *testing.T) { - // Test case 2: Non-proxy mode - config.ProxyMode = false - p = "/image.jpg?width=400&height=500" - id, jointPath, santizedPath := getId(p) - - // Verify the return values - parsed, _ := url.Parse(p) - expectedId := HashString(parsed.Path + "?width=400&height=500&max_width=&max_height=") - expectedPath := path.Join(config.Config.ImgPath, parsed.Path) - expectedSantizedPath := parsed.Path + "?width=400&height=500&max_width=&max_height=" - if id != expectedId || jointPath != expectedPath || santizedPath != expectedSantizedPath { - t.Errorf("Test case 2 failed: Expected (%s, %s, %s), but got (%s, %s, %s)", - expectedId, expectedPath, expectedSantizedPath, id, jointPath, santizedPath) - } - }) -} diff --git a/schedule/cache_clean.go b/schedule/cache_clean.go index 58b9c5c..1fcf07e 100644 --- a/schedule/cache_clean.go +++ b/schedule/cache_clean.go @@ -89,7 +89,7 @@ func clearCacheFiles(path string, maxCacheSizeBytes int64) error { } func CleanCache() { - log.Info("MaxCacheSize不为0,启动缓存清理服务") + log.Info("MaxCacheSize不为0,启动缓存清理服务...") ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() @@ -98,15 +98,16 @@ func CleanCache() { maxCacheSizeBytes := int64(config.Config.MaxCacheSize) * 1024 * 1024 if err := clearCacheFiles(config.Config.RemoteRawPath, maxCacheSizeBytes); err != nil { - log.Warn("无法清除远程原始缓存") + log.Warnf("清除远程原始缓存失败: %v", err) } if err := clearCacheFiles(config.Config.ExhaustPath, maxCacheSizeBytes); err != nil && err != os.ErrNotExist { - log.Warn("无法清除远程原始缓存") + log.Warnf("清除优化图像缓存失败: %v", err) } if err := clearCacheFiles(config.Config.MetadataPath, maxCacheSizeBytes); err != nil && err != os.ErrNotExist { - log.Warn("无法清除远程原始缓存") + log.Warnf("清除元数据缓存失败: %v", err) } + } }