package api import ( "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "net/url" "testing" "time" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) func TestRouterUploadPart(t *testing.T) { chiRouter := prepareRouter(t) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodPut, "/dkirillov/fix-object", nil) query := make(url.Values) query.Set("uploadId", "some-id") query.Set("partNumber", "1") r.URL.RawQuery = query.Encode() chiRouter.ServeHTTP(w, r) resp := readResponse(t, w) require.Equal(t, "UploadPart", resp.Method) } func TestRouterListMultipartUploads(t *testing.T) { chiRouter := prepareRouter(t) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/test-bucket", nil) query := make(url.Values) query.Set("uploads", "") r.URL.RawQuery = query.Encode() chiRouter.ServeHTTP(w, r) resp := readResponse(t, w) require.Equal(t, "ListMultipartUploads", resp.Method) } func TestRouterObjectWithSlashes(t *testing.T) { chiRouter := prepareRouter(t) bktName, objName := "dkirillov", "/fix/object" target := fmt.Sprintf("/%s/%s", bktName, objName) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodPut, target, nil) chiRouter.ServeHTTP(w, r) resp := readResponse(t, w) require.Equal(t, "PutObject", resp.Method) require.Equal(t, objName, resp.ReqInfo.ObjectName) } func TestRouterObjectEscaping(t *testing.T) { chiRouter := prepareRouter(t) bktName := "dkirillov" for _, tc := range []struct { name string expectedObjName string objName string }{ { name: "simple", expectedObjName: "object", objName: "object", }, { name: "with slashes", expectedObjName: "fix/object", objName: "fix/object", }, { name: "with slash escaped", expectedObjName: "/foo/bar", objName: "/foo%2fbar", }, { name: "with percentage escaped", expectedObjName: "fix/object%ac", objName: "fix/object%25ac", }, { name: "with awful mint name", expectedObjName: "äöüex ®©µÄÆÐÕæŒƕƩDž 01000000 0x40 \u0040 amȡȹɆple&0a!-_.*'()&$@=;:+,?<>.pdf", objName: "%C3%A4%C3%B6%C3%BCex%20%C2%AE%C2%A9%C2%B5%C3%84%C3%86%C3%90%C3%95%C3%A6%C5%92%C6%95%C6%A9%C7%85%2001000000%200x40%20%40%20am%C8%A1%C8%B9%C9%86ple%260a%21-_.%2A%27%28%29%26%24%40%3D%3B%3A%2B%2C%3F%3C%3E.pdf", }, } { t.Run(tc.name, func(t *testing.T) { target := fmt.Sprintf("/%s/%s", bktName, tc.objName) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodPut, target, nil) chiRouter.ServeHTTP(w, r) resp := readResponse(t, w) require.Equal(t, "PutObject", resp.Method) require.Equal(t, tc.expectedObjName, resp.ReqInfo.ObjectName) }) } } func prepareRouter(t *testing.T) *chi.Mux { cfg := Config{ Throttle: middleware.ThrottleOpts{ Limit: 10, BacklogTimeout: 30 * time.Second, }, Handler: &handlerMock{t: t}, Center: ¢erMock{}, Log: zaptest.NewLogger(t), Metrics: &metrics.AppMetrics{}, RequestMiddlewareSettings: &requestSettingsMock{}, } return NewRouter(cfg) } func readResponse(t *testing.T, w *httptest.ResponseRecorder) handlerResult { var res handlerResult resData, err := io.ReadAll(w.Result().Body) require.NoError(t, err) err = json.Unmarshal(resData, &res) require.NoErrorf(t, err, "actual body: '%s'", string(resData)) return res }