pkg/rest/request_test.go

135 lines
3.9 KiB
Go

/*
* Tencent is pleased to support the open source community by making
* 蓝鲸智云 - 配置平台 (BlueKing - CMDB) available.
* Copyright (C) 2025 Tencent. All rights reserved.
* Licensed under the MIT License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
* We undertake not to change the open source license (MIT license) applicable
* to the current version of the project delivered to anyone in the future.
*/
package rest
import (
"bytes"
"io"
"net/http"
"net/url"
"testing"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"git.ifooth.com/common/pkg/rest/codec"
)
// reqStruct for rest
type reqStruct struct {
Org string `json:"org" req:"path:org" in:"path=org"`
Name string `json:"name" req:"query:name" in:"query=name"`
Age int32 `json:"age" req:"form:age" in:"form=age"`
Bool bool `json:"bool" req:"query:bool" in:"query=bool"`
AgePtr *int `json:"agePtr" req:"header:age_ptr" in:"header=age_ptr"`
SliceStr []string `json:"sliceStr" req:"query:slice_str" in:"query=slice_str"`
Page int64 `json:"page"`
}
// newMockRequest creates a new mock request.
func newMockRequest(t testing.TB, method string, header map[string]string, body io.Reader) *http.Request {
req, err := http.NewRequest(method, "/{org}/vm/xxx?name=alices&age=20&age_ptr=21&slice_str=1&slice_str=2", body)
req.SetPathValue("org", "myOrg")
for k, v := range header {
req.Header.Set(k, v)
}
req.Body = io.NopCloser(body)
require.NoError(t, err)
return req
}
func TestDecode(t *testing.T) {
header := map[string]string{
"age_ptr": "21",
}
r := newMockRequest(t, http.MethodGet, header, nil)
req, err := decodeReq[reqStruct](r)
assert.NoError(t, err)
assert.Equal(t, "myOrg", req.Org)
assert.Equal(t, "alices", req.Name)
assert.Equal(t, lo.ToPtr(21), req.AgePtr)
assert.Equal(t, []string{"1", "2"}, req.SliceStr)
}
func TestFormDecode(t *testing.T) {
header := map[string]string{
"age_ptr": "21",
"Content-Type": "application/x-www-form-urlencoded",
}
formData := url.Values{}
formData.Set("age", "20")
r := newMockRequest(t, http.MethodPost, header, bytes.NewBufferString(formData.Encode()))
req, err := decodeReq[reqStruct](r)
assert.NoError(t, err)
assert.Equal(t, "myOrg", req.Org)
assert.Equal(t, "alices", req.Name)
assert.Equal(t, int32(20), req.Age)
assert.Equal(t, lo.ToPtr(21), req.AgePtr)
assert.Equal(t, []string{"1", "2"}, req.SliceStr)
}
func TestJsonDecode(t *testing.T) {
header := map[string]string{
"age_ptr": "21",
"Content-Type": "application/json",
}
jsonData := `{"page": 64}`
r := newMockRequest(t, http.MethodPost, header, bytes.NewBufferString(jsonData))
req, err := decodeReq[reqStruct](r)
assert.NoError(t, err)
assert.Equal(t, "myOrg", req.Org)
assert.Equal(t, "alices", req.Name)
assert.Equal(t, lo.ToPtr(21), req.AgePtr)
assert.Equal(t, []string{"1", "2"}, req.SliceStr)
assert.Equal(t, int64(64), req.Page)
}
func TestDecodeErr(t *testing.T) {
header := map[string]string{
"age_ptr": "21",
}
// array not support
type Req2 struct {
SliceStr [1]string `json:"sliceStr" req:"query:slice_str"`
}
r := newMockRequest(t, http.MethodGet, header, nil)
_, err := decodeReq[Req2](r)
assert.ErrorIs(t, err, codec.ErrUnsupportedType)
}
func BenchmarkDecodeReq(b *testing.B) {
for b.Loop() {
r := newMockRequest(b, http.MethodGet, nil, nil)
req, err := decodeReq[reqStruct](r)
if err != nil {
b.Fatal(err)
}
if req.Name != "alices" {
b.Fatal("name not equal")
}
}
}