diff --git a/pkg/cluster/layout_test.go b/pkg/cluster/layout_test.go index c7cafbd7e6..6078317435 100644 --- a/pkg/cluster/layout_test.go +++ b/pkg/cluster/layout_test.go @@ -18,10 +18,14 @@ package cluster import ( + "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestLayout(t *testing.T) { + assert := assert.New(t) l := Layout{} if len(l.OtherLease("member-1")) == 0 { @@ -67,4 +71,15 @@ func TestLayout(t *testing.T) { if len(l.WasmDataPrefix("pipeline", "wasm")) == 0 { t.Error("WasmDataPrefix empty") } + + statusObjectName := l.StatusObjectName("test-kind", "test-name") + assert.True(strings.Contains(statusObjectName, "test-kind")) + assert.True(strings.Contains(statusObjectName, "test-name")) + + statusNamespaceFormat := l.StatusNamespaceFormat("test-ns", "test-name") + assert.True(strings.Contains(statusNamespaceFormat, "test-ns")) + assert.True(strings.Contains(statusNamespaceFormat, "test-name")) + + assert.Equal(customDataPrefix, l.CustomDataPrefix()) + assert.Equal(customDataKindPrefix, l.CustomDataKindPrefix()) } diff --git a/pkg/filters/fallback/fallback_test.go b/pkg/filters/fallback/fallback_test.go index 9ceded4d87..4ea08545c0 100644 --- a/pkg/filters/fallback/fallback_test.go +++ b/pkg/filters/fallback/fallback_test.go @@ -49,6 +49,9 @@ mockBody: "mocked body" fb := kind.CreateInstance(spec) fb.Init() + assert.Equal("fallback", fb.Name()) + assert.Equal(kind, fb.Kind()) + assert.Equal(spec, fb.Spec()) ctx := context.New(tracing.NoopSpan) resp, err := httpprot.NewResponse(nil) diff --git a/pkg/filters/filters_test.go b/pkg/filters/filters_test.go index a3509f8c7f..d649b64727 100644 --- a/pkg/filters/filters_test.go +++ b/pkg/filters/filters_test.go @@ -21,8 +21,22 @@ import ( "testing" "github.com/megaease/easegress/pkg/util/yamltool" + "github.com/stretchr/testify/assert" ) +type mockSpec struct { + BaseSpec `yaml:",inline"` + Field string `yaml:"field" jsonschema:"required"` +} + +var mockKind = &Kind{ + Name: "Mock", + Description: "none", + Results: []string{}, + DefaultSpec: func() Spec { return &mockSpec{} }, + CreateInstance: func(spec Spec) Filter { return nil }, +} + func TestSpecInherit(t *testing.T) { type DerivedSpec struct { BaseSpec `yaml:",inline"` @@ -59,3 +73,37 @@ field1: abc t.Error("wrong pipeline") } } + +func TestNewSpec(t *testing.T) { + assert := assert.New(t) + + _, err := NewSpec(nil, "pipelin1", func() {}) + assert.NotNil(err, "marshal func should return err") + + _, err = NewSpec(nil, "pipeline1", "invalid spec") + assert.NotNil(err, "unmarshal 'invalid spec' to MetaSpec should return err") + + yamlStr := ` +name: filter +kind: Filter +` + rawSpec := map[string]interface{}{} + yamltool.Unmarshal([]byte(yamlStr), &rawSpec) + _, err = NewSpec(nil, "pipeline1", rawSpec) + assert.NotNil(err, "kind Filter not exist") + + // spec that work + kinds["Mock"] = mockKind + defer delete(kinds, "Mock") + yamlStr = ` +name: filter +kind: Mock +field: 123 +` + rawSpec = map[string]interface{}{} + yamltool.Unmarshal([]byte(yamlStr), &rawSpec) + spec, err := NewSpec(nil, "pipeline1", rawSpec) + assert.Nil(err) + assert.Nil(spec.Super()) + assert.NotEmpty(spec.YAMLConfig()) +} diff --git a/pkg/filters/headertojson/headertojson_test.go b/pkg/filters/headertojson/headertojson_test.go index a474d9d9ed..4173433bb7 100644 --- a/pkg/filters/headertojson/headertojson_test.go +++ b/pkg/filters/headertojson/headertojson_test.go @@ -21,6 +21,7 @@ import ( "bytes" "io" "net/http" + "strings" "testing" json "github.com/goccy/go-json" @@ -55,9 +56,19 @@ func TestHeaderToJSON(t *testing.T) { spec := defaultFilterSpec(&Spec{}) h := kind.CreateInstance(spec) h.Init() - + assert.Equal(spec.Name(), h.Name()) + assert.Equal(kind, h.Kind()) + assert.Equal(spec, h.Spec()) assert.Nil(h.Status()) + stdReq, err := http.NewRequest("", "/", nil) + assert.Nil(err) + req, err := httpprot.NewRequest(stdReq) + assert.Nil(err) + ctx := context.New(nil) + ctx.SetInputRequest(req) + assert.Equal("", h.Handle(ctx)) + newh := kind.CreateInstance(spec) newh.Inherit(h) newh.Close() @@ -165,4 +176,22 @@ func TestHandleHTTP(t *testing.T) { } } } + + { + // test http request with stream body + stdReq, err := http.NewRequest(http.MethodPost, "127.0.0.1", strings.NewReader("123")) + assert.Nil(err) + stdReq.Header.Add("x-username", "clientA") + + req, err := httpprot.NewRequest(stdReq) + assert.Nil(err) + req.FetchPayload(-1) + assert.True(req.IsStream()) + + ctx := context.New(nil) + ctx.SetInputRequest(req) + + ans := h2j.Handle(ctx) + assert.Equal(resultBodyReadErr, ans) + } } diff --git a/pkg/filters/httpbuilder/extrafuncs_test.go b/pkg/filters/httpbuilder/extrafuncs_test.go new file mode 100644 index 0000000000..3c01e7e159 --- /dev/null +++ b/pkg/filters/httpbuilder/extrafuncs_test.go @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package httpbuilder + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToFloat64(t *testing.T) { + assert := assert.New(t) + assert.Equal(float64(1), toFloat64(int8(1))) + assert.Equal(float64(1), toFloat64(int16(1))) + assert.Equal(float64(1), toFloat64(int32(1))) + assert.Equal(float64(1), toFloat64(int64(1))) + assert.Equal(float64(1), toFloat64(int(1))) + assert.Equal(float64(1), toFloat64(uint8(1))) + assert.Equal(float64(1), toFloat64(uint16(1))) + assert.Equal(float64(1), toFloat64(uint32(1))) + assert.Equal(float64(1), toFloat64(uint64(1))) + assert.Equal(float64(1), toFloat64(uint(1))) + assert.Equal(float64(1), toFloat64(uintptr(1))) + assert.Equal(float64(1), toFloat64("1")) + assert.Panics(func() { toFloat64("s") }) + assert.Panics(func() { toFloat64(func() {}) }) +} + +func TestExtraFuncs(t *testing.T) { + assert := assert.New(t) + assert.Equal(float64(123), extraFuncs["addf"].(func(a, b interface{}) float64)(120, 3)) + assert.Equal(float64(117), extraFuncs["subf"].(func(a, b interface{}) float64)(120, 3)) + assert.Equal(float64(360), extraFuncs["mulf"].(func(a, b interface{}) float64)(120, 3)) + assert.Equal(float64(40), extraFuncs["divf"].(func(a, b interface{}) float64)(120, 3)) + assert.Panics(func() { extraFuncs["divf"].(func(a, b interface{}) float64)(120, 0) }) + + assert.Equal("", extraFuncs["log"].(func(level, msg string) string)("debug", "debug")) + assert.Equal("", extraFuncs["log"].(func(level, msg string) string)("info", "info")) + assert.Equal("", extraFuncs["log"].(func(level, msg string) string)("warn", "warn")) + assert.Equal("", extraFuncs["log"].(func(level, msg string) string)("error", "error")) +} diff --git a/pkg/filters/httpbuilder/httpbuilder.go b/pkg/filters/httpbuilder/httpbuilder.go index b59bc9ec44..ff78e6541c 100644 --- a/pkg/filters/httpbuilder/httpbuilder.go +++ b/pkg/filters/httpbuilder/httpbuilder.go @@ -47,11 +47,6 @@ type ( Template string `yaml:"template" jsonschema:"required"` } - builderData struct { - Requests map[string]*request - Responses map[string]*response - } - request struct { *http.Request rawBody []byte @@ -161,6 +156,7 @@ func (r *response) JSONBody() (interface{}, error) { func (r *response) YAMLBody() (interface{}, error) { if r.parsedBody == nil { var v interface{} + fmt.Printf("rawbody %v", string(r.rawBody)) err := yaml.Unmarshal(r.rawBody, &v) if err != nil { return nil, err diff --git a/pkg/filters/httpbuilder/httpbuilder_test.go b/pkg/filters/httpbuilder/httpbuilder_test.go new file mode 100644 index 0000000000..e132ac83ea --- /dev/null +++ b/pkg/filters/httpbuilder/httpbuilder_test.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package httpbuilder + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuilderResponseBody(t *testing.T) { + assert := assert.New(t) + r := &response{ + Response: nil, + rawBody: []byte("abc"), + } + assert.Equal([]byte("abc"), r.RawBody()) + assert.Equal("abc", r.Body()) + _, err := r.JSONBody() + assert.NotNil(err) + + r = &response{ + Response: nil, + rawBody: []byte("123"), + } + _, err = r.JSONBody() + assert.Nil(err) + + r = &response{ + Response: nil, + rawBody: []byte("{{{{{}"), + } + _, err = r.YAMLBody() + assert.NotNil(err) + + r = &response{ + Response: nil, + rawBody: []byte("123"), + } + _, err = r.YAMLBody() + assert.Nil(err) +} diff --git a/pkg/filters/httpbuilder/httprequestbuilder_test.go b/pkg/filters/httpbuilder/httprequestbuilder_test.go index 336767d55f..ed284d518d 100644 --- a/pkg/filters/httpbuilder/httprequestbuilder_test.go +++ b/pkg/filters/httpbuilder/httprequestbuilder_test.go @@ -25,8 +25,10 @@ import ( "testing" "github.com/megaease/easegress/pkg/context" + "github.com/megaease/easegress/pkg/filters" "github.com/megaease/easegress/pkg/logger" "github.com/megaease/easegress/pkg/protocols/httpprot" + "github.com/megaease/easegress/pkg/util/yamltool" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" ) @@ -321,4 +323,85 @@ field2: value2 assert.Nil(err) assert.Equal("body value1 value2", string(data)) } + + // use default method + yml = `template: | + url: http://www.facebook.com +` + { + spec := &HTTPRequestBuilderSpec{} + yaml.Unmarshal([]byte(yml), spec) + rb := getRequestBuilder(spec) + defer rb.Close() + + ctx := context.New(nil) + ctx.UseNamespace("", "test") + + res := rb.Handle(ctx) + assert.Empty(res) + testReq := ctx.GetRequest("test").(*httpprot.Request) + assert.Equal(http.MethodGet, testReq.Std().Method) + } + + // use default url + yml = `template: | + method: delete +` + { + spec := &HTTPRequestBuilderSpec{} + yaml.Unmarshal([]byte(yml), spec) + rb := getRequestBuilder(spec) + defer rb.Close() + + ctx := context.New(nil) + ctx.UseNamespace("", "test") + + res := rb.Handle(ctx) + assert.Empty(res) + testReq := ctx.GetRequest("test").(*httpprot.Request) + assert.Equal(http.MethodDelete, testReq.Std().Method) + assert.Equal("/", testReq.Std().URL.String()) + } + + // build request failed + yml = `template: | + url: http://192.168.0.%31:8080/ +` + { + spec := &HTTPRequestBuilderSpec{} + yaml.Unmarshal([]byte(yml), spec) + rb := getRequestBuilder(spec) + defer rb.Close() + + ctx := context.New(nil) + ctx.UseNamespace("", "test") + + res := rb.Handle(ctx) + assert.NotEmpty(res) + } +} + +func TestHTTPRequestBuilder(t *testing.T) { + assert := assert.New(t) + + assert.Equal(&HTTPRequestBuilderSpec{}, httpRequestBuilderKind.DefaultSpec()) + yamlStr := ` +name: requestBuilder +kind: HTTPRequestBuilder +template: | + method: Delete +` + rawSpec := map[string]interface{}{} + yamltool.Unmarshal([]byte(yamlStr), &rawSpec) + spec, err := filters.NewSpec(nil, "pipeline1", rawSpec) + assert.Nil(err) + requestBuilder := httpRequestBuilderKind.CreateInstance(spec).(*HTTPRequestBuilder) + assert.Equal("requestBuilder", requestBuilder.Name()) + assert.Equal(httpRequestBuilderKind, requestBuilder.Kind()) + assert.Equal(spec, requestBuilder.Spec()) + requestBuilder.Init() + + newRequestBuilder := httpRequestBuilderKind.CreateInstance(spec) + newRequestBuilder.Inherit(requestBuilder) + assert.Nil(newRequestBuilder.Status()) } diff --git a/pkg/filters/httpbuilder/httpresponsebuilder_test.go b/pkg/filters/httpbuilder/httpresponsebuilder_test.go index 6c2d18725b..6334f4e95a 100644 --- a/pkg/filters/httpbuilder/httpresponsebuilder_test.go +++ b/pkg/filters/httpbuilder/httpresponsebuilder_test.go @@ -24,8 +24,10 @@ import ( "testing" "github.com/megaease/easegress/pkg/context" + "github.com/megaease/easegress/pkg/filters" "github.com/megaease/easegress/pkg/logger" "github.com/megaease/easegress/pkg/protocols/httpprot" + "github.com/megaease/easegress/pkg/util/yamltool" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" ) @@ -233,4 +235,46 @@ field2: value2 assert.Nil(err) assert.Equal("body value1 value2", string(data)) } + + // invalid status code + yml = `template: | + statusCode: 800 +` + { + spec := &HTTPResponseBuilderSpec{} + yaml.Unmarshal([]byte(yml), spec) + rb := getResponseBuilder(spec) + defer rb.Close() + + ctx := context.New(nil) + + ctx.UseNamespace("", "test") + res := rb.Handle(ctx) + assert.NotEmpty(res) + } +} + +func TestHTTPResponseBuilder(t *testing.T) { + assert := assert.New(t) + + assert.Equal(&HTTPResponseBuilderSpec{}, httpResponseBuilderKind.DefaultSpec()) + yamlStr := ` +name: responseBuilder +kind: HTTPResponseBuilder +template: | + statusCode: 200 +` + rawSpec := map[string]interface{}{} + yamltool.Unmarshal([]byte(yamlStr), &rawSpec) + spec, err := filters.NewSpec(nil, "pipeline1", rawSpec) + assert.Nil(err) + responseBuilder := httpResponseBuilderKind.CreateInstance(spec).(*HTTPResponseBuilder) + assert.Equal("responseBuilder", responseBuilder.Name()) + assert.Equal(httpResponseBuilderKind, responseBuilder.Kind()) + assert.Equal(spec, responseBuilder.Spec()) + responseBuilder.Init() + + newResponseBuilder := httpResponseBuilderKind.CreateInstance(spec) + newResponseBuilder.Inherit(responseBuilder) + assert.Nil(newResponseBuilder.Status()) } diff --git a/pkg/filters/kafka/kafka_test.go b/pkg/filters/kafka/kafka_test.go index 7f70ce6699..e2eda4e558 100644 --- a/pkg/filters/kafka/kafka_test.go +++ b/pkg/filters/kafka/kafka_test.go @@ -86,7 +86,12 @@ func TestKafka(t *testing.T) { } filterSpec := defaultFilterSpec(spec) k := kind.CreateInstance(filterSpec) + assert.Equal(&Spec{}, kind.DefaultSpec()) assert.Panics(func() { k.Init() }, "kafka should panic for invalid backend") + assert.Equal(spec.BaseSpec.MetaSpec.Name, k.Name()) + assert.Equal(kind, k.Kind()) + assert.Equal(filterSpec, k.Spec()) + assert.Nil(k.Status()) kafka := Kafka{ producer: newMockAsyncProducer(), @@ -103,6 +108,9 @@ func TestKafka(t *testing.T) { value, err := msg.Value.Encode() assert.Nil(err) assert.Equal("text", string(value)) + + newK := kind.CreateInstance(filterSpec) + assert.Panics(func() { newK.Inherit(k) }) } func TestKafkaWithKVMap(t *testing.T) { diff --git a/pkg/filters/kafkabackend/kafka_test.go b/pkg/filters/kafkabackend/kafka_test.go index af362e6293..b0e98aa077 100644 --- a/pkg/filters/kafkabackend/kafka_test.go +++ b/pkg/filters/kafkabackend/kafka_test.go @@ -85,6 +85,9 @@ func TestKafka(t *testing.T) { assert.Nil(k.Status()) assert.Panics(func() { k.Init() }, "no valid backend should panic") + assert.Equal(spec.Name(), k.Name()) + assert.Equal(kind, k.Kind()) + assert.Equal(spec, k.Spec()) newK := &Kafka{} assert.Panics(func() { newK.Inherit(k) }) diff --git a/pkg/filters/registry.go b/pkg/filters/registry.go index 80578f6f52..bd99c37e8b 100644 --- a/pkg/filters/registry.go +++ b/pkg/filters/registry.go @@ -39,12 +39,12 @@ func Register(k *Kind) { sort.Strings(k.Results) // Checking results. - last := "" + resultMap := map[string]struct{}{} for _, result := range k.Results { - if result == last { + if _, ok := resultMap[result]; ok { panic(fmt.Errorf("duplicated result: %s", result)) } - last = result + resultMap[result] = struct{}{} } kinds[k.Name] = k diff --git a/pkg/filters/registry_test.go b/pkg/filters/registry_test.go new file mode 100644 index 0000000000..b904676368 --- /dev/null +++ b/pkg/filters/registry_test.go @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package filters + +import ( + "testing" + + "github.com/megaease/easegress/pkg/supervisor" + "github.com/stretchr/testify/assert" +) + +var duplicatedResult = &Kind{ + Name: "DuplicatedResult", + Description: "none", + Results: []string{"1", "2", "1"}, + DefaultSpec: func() Spec { return &mockSpec{} }, + CreateInstance: func(spec Spec) Filter { return nil }, +} + +func TestRegister(t *testing.T) { + assert := assert.New(t) + + // test Unregister + Register(mockKind) + assert.NotNil(GetKind(mockKind.Name)) + Unregister(mockKind.Name) + assert.Nil(GetKind(mockKind.Name)) + + // test ResetRegistry + Register(mockKind) + assert.NotNil(GetKind(mockKind.Name)) + ResetRegistry() + assert.Nil(GetKind(mockKind.Name)) + + // test Register panic with invalid kind + Register(mockKind) + assert.Panics(func() { Register(mockKind) }) + assert.Panics(func() { Register(duplicatedResult) }) + + baseSpec := &BaseSpec{ + MetaSpec: supervisor.MetaSpec{ + Kind: mockKind.Name, + }, + } + assert.Nil(Create(baseSpec)) + + WalkKind(func(k *Kind) bool { + assert.Equal(mockKind.Name, k.Name) + return false + }) + + k := &Kind{} + assert.Panics(func() { Register(k) }) + + assert.Nil(Create(&BaseSpec{ + MetaSpec: supervisor.MetaSpec{ + Kind: "UnRegistryKind", + }, + })) +} diff --git a/pkg/filters/requestadaptor/requestadaptor_test.go b/pkg/filters/requestadaptor/requestadaptor_test.go index 80c621a37f..24ebb47224 100644 --- a/pkg/filters/requestadaptor/requestadaptor_test.go +++ b/pkg/filters/requestadaptor/requestadaptor_test.go @@ -70,6 +70,8 @@ func TestRequestAdaptor(t *testing.T) { ra.Init() assert.Equal(Kind, ra.Kind().Name) assert.Nil(ra.Status()) + assert.Equal(spec.Name(), ra.Name()) + assert.Equal(spec, ra.Spec()) newRA := kind.CreateInstance(spec) newRA.Inherit(ra) diff --git a/pkg/filters/responseadaptor/responseadaptor_test.go b/pkg/filters/responseadaptor/responseadaptor_test.go index 0d52d7931c..50ccfff4cb 100644 --- a/pkg/filters/responseadaptor/responseadaptor_test.go +++ b/pkg/filters/responseadaptor/responseadaptor_test.go @@ -19,15 +19,21 @@ package responseadaptor import ( "io" + "net/http" + "net/http/httptest" "os" + "strings" "testing" "github.com/megaease/easegress/pkg/context" "github.com/megaease/easegress/pkg/filters" "github.com/megaease/easegress/pkg/logger" "github.com/megaease/easegress/pkg/protocols/httpprot" + "github.com/megaease/easegress/pkg/tracing" + "github.com/megaease/easegress/pkg/util/readers" "github.com/megaease/easegress/pkg/util/yamltool" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -37,6 +43,8 @@ func TestMain(m *testing.M) { } func TestResponseAdaptor(t *testing.T) { + assert := assert.New(t) + yamlSpec := ` kind: ResponseAdaptor name: ra @@ -44,9 +52,14 @@ header: del: ["X-Del"] add: "X-Mock": "mockedHeaderValue" + set: + "X-Set": "setHeaderValue" body: "copyright" ` ra := doTest(t, yamlSpec, nil) + assert.Equal("ra", ra.Name()) + assert.Equal(kind, ra.Kind()) + assert.Equal("ResponseAdaptor", ra.Spec().Kind()) yamlSpec = ` kind: ResponseAdaptor @@ -55,9 +68,12 @@ header: del: ["X-Del"] add: "X-Mock": "mockedHeaderValue" + set: + "X-Set": "setHeaderValue" body: "copyright" ` - doTest(t, yamlSpec, ra) + ra = doTest(t, yamlSpec, ra) + ra.Close() } func doTest(t *testing.T, yamlSpec string, prev *ResponseAdaptor) *ResponseAdaptor { @@ -87,6 +103,7 @@ func doTest(t *testing.T, yamlSpec string, prev *ResponseAdaptor) *ResponseAdapt ra.Handle(ctx) assert.Equal("mockedHeaderValue", resp.Std().Header.Get("X-Mock")) assert.Equal("", resp.Std().Header.Get("X-Del")) + assert.Equal("setHeaderValue", resp.Std().Header.Get("X-Set")) body, err := io.ReadAll(resp.GetPayload()) assert.Nil(err) @@ -95,3 +112,117 @@ func doTest(t *testing.T, yamlSpec string, prev *ResponseAdaptor) *ResponseAdapt ra.Status() return ra.(*ResponseAdaptor) } + +func getCtx(t *testing.T, r *http.Response) *context.Context { + ctx := context.New(tracing.NoopSpan) + resp, err := httpprot.NewResponse(r) + require.Nil(t, err) + resp.FetchPayload(1024 * 1024) + ctx.SetInputResponse(resp) + return ctx +} + +func TestCompressDecompress(t *testing.T) { + assert := assert.New(t) + { + // invalid decompress parameter + spec := &Spec{ + Decompress: "invalid", + } + ra := &ResponseAdaptor{ + spec: spec, + } + assert.Panics(func() { ra.Init() }) + } + + { + // invalid compress parameter + spec := &Spec{ + Compress: "invalid", + } + ra := &ResponseAdaptor{ + spec: spec, + } + assert.Panics(func() { ra.Init() }) + } + { + // both set compress and decompress parameter + spec := &Spec{ + Decompress: "gzip", + Compress: "gzip", + } + ra := &ResponseAdaptor{ + spec: spec, + } + assert.Panics(func() { ra.Init() }) + } + + { + // test compress + spec := &Spec{ + Compress: "gzip", + } + ra := &ResponseAdaptor{ + spec: spec, + } + ra.Init() + + w := httptest.NewRecorder() + _, err := w.WriteString("hello") + assert.Nil(err) + resp := w.Result() + ctx := getCtx(t, resp) + ra.Handle(ctx) + zr, err := readers.NewGZipDecompressReader(ctx.GetInputResponse().GetPayload()) + assert.Nil(err) + data, err := io.ReadAll(zr) + zr.Close() + assert.Nil(err) + assert.Equal("hello", string(data)) + } + { + // test decompress + spec := &Spec{ + Decompress: "gzip", + } + ra := &ResponseAdaptor{ + spec: spec, + } + ra.Init() + + // set compressed data + w := httptest.NewRecorder() + zr := readers.NewGZipCompressReader(strings.NewReader("hello")) + data, err := io.ReadAll(zr) + assert.Nil(err) + zr.Close() + _, err = w.Write(data) + assert.Nil(err) + resp := w.Result() + resp.Header.Set(keyContentEncoding, "gzip") + + ctx := getCtx(t, resp) + ra.Handle(ctx) + assert.Equal("hello", string(ctx.GetInputResponse().RawPayload())) + } + { + // test decompress fail + spec := &Spec{ + Decompress: "gzip", + } + ra := &ResponseAdaptor{ + spec: spec, + } + ra.Init() + + w := httptest.NewRecorder() + _, err := w.WriteString("hello") + assert.Nil(err) + resp := w.Result() + resp.Header.Set(keyContentEncoding, "gzip") + + ctx := getCtx(t, resp) + res := ra.Handle(ctx) + assert.Equal(resultDecompressFailed, res) + } +} diff --git a/pkg/object/httpserver/runtime_test.go b/pkg/object/httpserver/runtime_test.go index 90a22b365c..f86efea59a 100644 --- a/pkg/object/httpserver/runtime_test.go +++ b/pkg/object/httpserver/runtime_test.go @@ -84,6 +84,9 @@ https: false assert.NoError(err) assert.True(r.needRestartServer(superSpec.ObjectSpec().(*Spec))) + res := r.Status().ToMetrics("mock") + assert.NotNil(res) + r.Close() time.Sleep(100 * time.Millisecond) } diff --git a/pkg/object/meshcontroller/spec/selector_test.go b/pkg/object/meshcontroller/spec/selector_test.tmpgo similarity index 100% rename from pkg/object/meshcontroller/spec/selector_test.go rename to pkg/object/meshcontroller/spec/selector_test.tmpgo diff --git a/pkg/protocols/httpprot/request_test.go b/pkg/protocols/httpprot/request_test.go index 6fbe74a250..21884b3bbe 100644 --- a/pkg/protocols/httpprot/request_test.go +++ b/pkg/protocols/httpprot/request_test.go @@ -19,13 +19,16 @@ package httpprot import ( "context" + "crypto/tls" "io" "net/http" "net/url" "strings" "testing" + "github.com/megaease/easegress/pkg/util/readers" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRequest(t *testing.T) { @@ -97,3 +100,111 @@ func TestRequest(t *testing.T) { request.SetPath("/foo/bar") assert.Equal("/foo/bar", request.Path()) } + +func getRequest(t *testing.T, method string, url string, body io.Reader) *Request { + stdReq, err := http.NewRequest(method, url, body) + require.Nil(t, err) + req, err := NewRequest(stdReq) + require.Nil(t, err) + return req + +} + +func TestRequest2(t *testing.T) { + assert := assert.New(t) + { + // when FetchPayload with -1, payload is stream + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", strings.NewReader("123")) + + err := req.FetchPayload(-1) + assert.Nil(err) + assert.True(req.IsStream()) + req.Close() + } + + { + // test set payload + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", nil) + + req.SetPayload(nil) + assert.Nil(req.RawPayload()) + + req.SetPayload("") + assert.Equal(http.NoBody, req.GetPayload()) + + req.SetPayload("123") + assert.Equal([]byte("123"), req.RawPayload()) + assert.Equal(int64(3), req.PayloadSize()) + + assert.Panics(func() { req.SetPayload(123) }) + + req.SetPayload(strings.NewReader("123")) + assert.True(req.IsStream()) + + reader := readers.NewByteCountReader(strings.NewReader("123")) + req.SetPayload(reader) + assert.Equal(reader, req.GetPayload()) + } + + { + // when FetchPayload with -1, payload is stream + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", strings.NewReader("123")) + + err := req.FetchPayload(0) + assert.Nil(err) + assert.False(req.IsStream()) + req.Close() + } + + { + // when ContentLength bigger than FetchPayload + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", strings.NewReader("123")) + req.Std().ContentLength = 3 + + err := req.FetchPayload(1) + assert.Equal(ErrRequestEntityTooLarge, err) + req.Close() + } + + { + // when ContentLength is zero + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", http.NoBody) + req.Std().ContentLength = 0 + + err := req.FetchPayload(100) + assert.Nil(err) + req.Close() + } + + { + // unknown context length + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", strings.NewReader("123123123123")) + req.Std().ContentLength = -1 + err := req.FetchPayload(100) + assert.Nil(err) + req.Close() + } + + { + // unknown context length and actual context length longer than FetchPayload + req := getRequest(t, http.MethodGet, "http://127.0.0.1:8888", strings.NewReader("123123123123")) + req.Std().ContentLength = -1 + err := req.FetchPayload(2) + assert.Equal(ErrRequestEntityTooLarge, err) + req.Close() + } + + { + stdReq, err := http.NewRequest(http.MethodGet, "/", nil) + assert.Nil(err) + assert.Empty(stdReq.URL.Scheme) + assert.Equal("http", RequestScheme(stdReq)) + + stdReq.Header.Add("X-Forwarded-Proto", "fakeProtocol") + assert.Equal("fakeProtocol", RequestScheme(stdReq)) + + stdReq.Header.Del("X-Forwarded-Proto") + stdReq.TLS = &tls.ConnectionState{} + assert.Equal("https", RequestScheme(stdReq)) + } +} diff --git a/pkg/protocols/httpprot/response.go b/pkg/protocols/httpprot/response.go index 3de5fbaa04..525db6275a 100644 --- a/pkg/protocols/httpprot/response.go +++ b/pkg/protocols/httpprot/response.go @@ -82,7 +82,7 @@ func (r *Response) FetchPayload(maxPayloadSize int64) error { } if maxPayloadSize < 0 { - r.SetPayload(r.Request.Body) + r.SetPayload(r.Response.Body) return nil } diff --git a/pkg/protocols/httpprot/response_test.go b/pkg/protocols/httpprot/response_test.go index 01f0af0135..19cbcc2f8f 100644 --- a/pkg/protocols/httpprot/response_test.go +++ b/pkg/protocols/httpprot/response_test.go @@ -21,8 +21,10 @@ import ( "io" "net/http" "net/http/httptest" + "strings" "testing" + "github.com/megaease/easegress/pkg/util/readers" "github.com/stretchr/testify/assert" ) @@ -92,3 +94,102 @@ func TestResponse(t *testing.T) { resp.SetStatusCode(http.StatusBadRequest) assert.Equal(http.StatusBadRequest, resp.StatusCode()) } + +func TestResponse2(t *testing.T) { + assert := assert.New(t) + { + // when FetchPayload with -1, payload is stream + resp, err := NewResponse(nil) + assert.Nil(err) + + err = resp.FetchPayload(-1) + assert.Nil(err) + assert.True(resp.IsStream()) + resp.Close() + } + + { + // test set payload + resp, err := NewResponse(nil) + assert.Nil(err) + + resp.SetPayload(nil) + assert.Nil(resp.RawPayload()) + + resp.SetPayload("") + assert.Equal(http.NoBody, resp.GetPayload()) + + resp.SetPayload("123") + assert.Equal([]byte("123"), resp.RawPayload()) + assert.Equal(int64(3), resp.PayloadSize()) + + assert.Panics(func() { resp.SetPayload(123) }) + + resp.SetPayload(strings.NewReader("123")) + assert.True(resp.IsStream()) + + reader := readers.NewByteCountReader(strings.NewReader("123")) + resp.SetPayload(reader) + assert.Equal(reader, resp.GetPayload()) + } + + { + // when FetchPayload with -1, payload is stream + stdResp := &http.Response{Body: io.NopCloser(strings.NewReader("123"))} + resp, err := NewResponse(stdResp) + assert.Nil(err) + + err = resp.FetchPayload(0) + assert.Nil(err) + assert.False(resp.IsStream()) + resp.Close() + } + + { + // when ContentLength bigger than FetchPayload + stdResp := &http.Response{Body: io.NopCloser(strings.NewReader("123"))} + stdResp.ContentLength = 3 + resp, err := NewResponse(stdResp) + assert.Nil(err) + + err = resp.FetchPayload(1) + assert.Equal(ErrResponseEntityTooLarge, err) + resp.Close() + } + + { + // when ContentLength is zero + stdResp := &http.Response{Body: http.NoBody} + stdResp.ContentLength = 0 + resp, err := NewResponse(stdResp) + assert.Nil(err) + + err = resp.FetchPayload(100) + assert.Nil(err) + resp.Close() + } + + { + // unknown context length + stdResp := &http.Response{Body: io.NopCloser(strings.NewReader("123123123123"))} + stdResp.ContentLength = -1 + resp, err := NewResponse(stdResp) + assert.Nil(err) + + err = resp.FetchPayload(100) + assert.Nil(err) + resp.Close() + } + + { + // unknown context length and actual context length longer than FetchPayload + stdResp := &http.Response{Body: io.NopCloser(strings.NewReader("123123123123"))} + stdResp.ContentLength = -1 + resp, err := NewResponse(stdResp) + assert.Nil(err) + + err = resp.FetchPayload(2) + assert.Equal(ErrResponseEntityTooLarge, err) + resp.Close() + } +} diff --git a/pkg/util/readers/bytecountreader_test.go b/pkg/util/readers/bytecountreader_test.go new file mode 100644 index 0000000000..eed97fbab0 --- /dev/null +++ b/pkg/util/readers/bytecountreader_test.go @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package readers + +import ( + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestByteCountReader(t *testing.T) { + assert := assert.New(t) + + br := NewByteCountReader(io.NopCloser(strings.NewReader("123"))) + data, err := io.ReadAll(br) + assert.Nil(err) + assert.Equal("123", string(data)) + assert.Equal(len([]byte("123")), br.BytesRead()) + assert.True(br.SawEOF()) + assert.True(br.SawErrorOrEOF()) + assert.Nil(br.Error()) + assert.Nil(br.Close()) +} diff --git a/pkg/util/readers/callbackreader_test.go b/pkg/util/readers/callbackreader_test.go new file mode 100644 index 0000000000..8517ee7624 --- /dev/null +++ b/pkg/util/readers/callbackreader_test.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package readers + +import ( + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCallbackReader(t *testing.T) { + assert := assert.New(t) + cr := NewCallbackReader(io.NopCloser(strings.NewReader("123"))) + bytesRead := 0 + closed := false + cr.OnAfter(func(total int, p []byte, err error) { + bytesRead = total + }) + cr.OnClose(func() { + closed = true + }) + + data, err := io.ReadAll(cr) + assert.Nil(err) + assert.Equal("123", string(data)) + assert.Equal(len([]byte("123")), bytesRead) + + cr.Close() + assert.True(closed) +} diff --git a/pkg/util/readers/gzipcompressreader_test.go b/pkg/util/readers/gzipcompressreader_test.go new file mode 100644 index 0000000000..3ebc5ff1be --- /dev/null +++ b/pkg/util/readers/gzipcompressreader_test.go @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +package readers + +import ( + "bytes" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGzipCompressDecompressReader(t *testing.T) { + assert := assert.New(t) + + var str string + for i := 0; i < 200; i++ { + str += "123123123124234asdjflasjflasfjlaksnvalknfaslkfnalkfnaslfjasfasfasfas" + } + compressReader := NewGZipCompressReader(strings.NewReader(str)) + data, err := io.ReadAll(compressReader) + assert.Nil(err) + err = compressReader.Close() + assert.Nil(err) + + assert.NotEqual(str, string(data)) + assert.Less(10*len(string(data)), len(str)) + + decompressReader, err := NewGZipDecompressReader(bytes.NewReader(data)) + assert.Nil(err) + data, err = io.ReadAll(decompressReader) + assert.Nil(err) + assert.Equal(str, string(data)) + err = decompressReader.Close() + assert.Nil(err) +} diff --git a/pkg/util/readers/readerat_test.go b/pkg/util/readers/readerat_test.go index e4020468db..495a35988e 100644 --- a/pkg/util/readers/readerat_test.go +++ b/pkg/util/readers/readerat_test.go @@ -20,52 +20,54 @@ package readers import ( "bytes" "io" + "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestReaderAt(t *testing.T) { - r := bytes.NewReader([]byte("abcdefghijklmnopqrstuvwxyz")) + assert := assert.New(t) + r := bytes.NewReader([]byte("abcdefghijklmnopqrstuvwxyz")) ra := NewReaderAt(r) r1 := NewReaderAtReader(ra, 0) buf := make([]byte, 10) n, err := r1.Read(buf) - if n != 10 || err != nil { - t.Errorf("expect 10 bytes and no error, but got: %d, %v", n, err) - } + assert.Nil(err) + assert.Equal(10, n) n, err = r1.Read(buf) - if n != 10 || err != nil { - t.Errorf("expect 10 bytes and no error, but got: %d, %v", n, err) - } + assert.Nil(err) + assert.Equal(10, n) n, err = r1.Read(buf) - if n != 6 { - t.Errorf("expect 6 bytes, but got: %d", n) - } + assert.Nil(err) + assert.Equal(6, n) n, err = r1.Read(buf) - if n != 0 || err != io.EOF { - t.Errorf("expect 0 bytes and EOF, but got: %d, %v", n, err) - } + assert.Equal(io.EOF, err) + assert.Equal(0, n) r1 = NewReaderAtReader(ra, 7) n, err = r1.Read(buf) - if n != 10 || err != nil { - t.Errorf("expect 10 bytes and no error, but got: %d, %v", n, err) - } + assert.Nil(err) + assert.Equal(10, n) n, err = r1.Read(buf) - if n != 9 { - t.Errorf("expect 6 bytes, but got: %d", n) - } + assert.Equal(io.EOF, err) + assert.Equal(9, n) n, err = r1.Read(buf) - if n != 0 || err != io.EOF { - t.Errorf("expect 0 bytes and EOF, but got: %d, %v", n, err) - } - + assert.Equal(io.EOF, err) + assert.Equal(0, n) ra.Close() + + ra = NewReaderAt(nil) + assert.Nil(ra.Close()) + + ra = NewReaderAt(io.NopCloser(strings.NewReader("123"))) + assert.Nil(ra.Close()) } diff --git a/pkg/util/stringtool/stringtool_test.go b/pkg/util/stringtool/stringtool_test.go index 22d4a316ef..610805f906 100644 --- a/pkg/util/stringtool/stringtool_test.go +++ b/pkg/util/stringtool/stringtool_test.go @@ -23,6 +23,15 @@ import ( "github.com/stretchr/testify/assert" ) +func TestStringTool(t *testing.T) { + assert := assert.New(t) + + assert.Equal("123", Cat("1", "2", "3")) + assert.True(StrInSlice("123", []string{"000", "111", "123"})) + assert.False(StrInSlice("123", []string{"000", "111"})) + assert.Equal([]string{"123"}, DeleteStrInSlice([]string{"123", "456"}, "456")) +} + func TestIsAllEmpty(t *testing.T) { assert := assert.New(t)