mirror of
https://github.com/woodchen-ink/webp_server_go.git
synced 2025-07-18 05:32:02 +08:00
chore: Refactor workflow and Makefile, remove test files
This commit is contained in:
parent
4aea178ab0
commit
f8b23a88f3
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -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.
|
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -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.
|
|
28
.github/workflows/release_docker_image.yaml
vendored
28
.github/workflows/release_docker_image.yaml
vendored
@ -1,4 +1,5 @@
|
|||||||
name: Build docker images
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
@ -16,9 +17,27 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
@ -31,11 +50,12 @@ jobs:
|
|||||||
username: woodchen
|
username: woodchen
|
||||||
password: ${{ secrets.ACCESS_TOKEN }}
|
password: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Dockerfile
|
file: Dockerfile.multi
|
||||||
push: true
|
push: true
|
||||||
tags: woodchen/${{ env.IMAGE_NAME }}:latest
|
tags: woodchen/${{ env.IMAGE_NAME }}:latest
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|
||||||
|
18
Dockerfile.multi
Normal file
18
Dockerfile.multi
Normal file
@ -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"]
|
5
Makefile
5
Makefile
@ -33,11 +33,8 @@ static-check: install-staticcheck
|
|||||||
tools/bin/staticcheck -checks all,-ST1000 ./...
|
tools/bin/staticcheck -checks all,-ST1000 ./...
|
||||||
GO111MODULE=on tools/bin/golangci-lint run -v $$($(PACKAGE_DIRECTORIES)) --config .golangci.yml
|
GO111MODULE=on tools/bin/golangci-lint run -v $$($(PACKAGE_DIRECTORIES)) --config .golangci.yml
|
||||||
|
|
||||||
test:
|
|
||||||
go test -v -coverprofile=coverage.txt -covermode=atomic ./...
|
|
||||||
|
|
||||||
clean:
|
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:
|
||||||
DOCKER_BUILDKIT=1 docker build -t webpsh/webps .
|
DOCKER_BUILDKIT=1 docker build -t webpsh/webps .
|
||||||
|
@ -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))
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
@ -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])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -89,7 +89,7 @@ func clearCacheFiles(path string, maxCacheSizeBytes int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CleanCache() {
|
func CleanCache() {
|
||||||
log.Info("MaxCacheSize不为0,启动缓存清理服务")
|
log.Info("MaxCacheSize不为0,启动缓存清理服务...")
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
ticker := time.NewTicker(1 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
@ -98,15 +98,16 @@ func CleanCache() {
|
|||||||
maxCacheSizeBytes := int64(config.Config.MaxCacheSize) * 1024 * 1024
|
maxCacheSizeBytes := int64(config.Config.MaxCacheSize) * 1024 * 1024
|
||||||
|
|
||||||
if err := clearCacheFiles(config.Config.RemoteRawPath, maxCacheSizeBytes); err != nil {
|
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 {
|
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 {
|
if err := clearCacheFiles(config.Config.MetadataPath, maxCacheSizeBytes); err != nil && err != os.ErrNotExist {
|
||||||
log.Warn("无法清除远程原始缓存")
|
log.Warnf("清除元数据缓存失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user