blob: c21ad3aff9514b617f7e156806add8588e76a423 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 chain
import (
"context"
"errors"
"github.com/apache/servicecomb-service-center/pkg/util"
"testing"
"time"
)
const (
times = 1000000
count = 10
)
func init() {
for i := 0; i < count; i++ {
RegisterHandler("_bench_handlers_", &handler{})
}
}
type handler struct {
}
func (h *handler) Handle(i *Invocation) {
i.Next()
}
func syncFunc(i int) {
if i >= count {
return
}
syncFunc(i + 1)
}
func BenchmarkInvocationOption(b *testing.B) {
var (
op InvocationOp
f = func(r Result) {}
opts = []InvocationOption{WithFunc(f), WithAsyncFunc(f)}
)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
for _, opt := range opts {
op = opt(op)
}
}
})
b.ReportAllocs()
// 50000000 26.8 ns/op 0 B/op 0 allocs/op
}
func BenchmarkChain(b *testing.B) {
var (
ctx = util.NewStringContext(context.Background())
f = func(r Result) {}
)
b.N = times
b.ResetTimer()
for i := 0; i < b.N; i++ {
inv := NewInvocation(ctx, NewChain("_bench_chain_", Handlers("_bench_handlers_")))
inv.Invoke(f)
}
b.ReportAllocs()
// 1000000 735 ns/op 80 B/op 1 allocs/op
}
type mockHandler struct {
}
func (h *mockHandler) Handle(i *Invocation) {
x := i.Context().Value("x").(int)
switch x {
case 1:
i.Success(x)
case 2:
i.Fail(errors.New("error"), x)
case 3:
i.Next(WithFunc(func(r Result) {
i.WithContext("x", x*x)
}))
case 4:
i.Next(WithAsyncFunc(func(r Result) {
i.WithContext("x", x*x)
ch, _ := i.Context().Value("ch").(chan struct{})
ch <- struct{}{}
}))
case 5:
panic(errors.New("error"))
case 6:
i.Next(WithFunc(func(r Result) {
panic(errors.New("error"))
}))
case 7:
i.Next(WithAsyncFunc(func(r Result) {
panic(errors.New("error"))
}))
default:
i.WithContext("x", x-1)
i.Next()
}
}
func TestChain_Next(t *testing.T) {
h := &mockHandler{}
hs := Handlers("test")
hs = []Handler{h, h, h}
x := 0
ch := NewChain("test", hs)
if ch.Name() != "test" {
t.Fatalf("TestChain_Next")
}
i := NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if !r.OK || i.Context().Value("x").(int) != -len(hs) {
t.Fatalf("TestChain_Next")
}
})
x = 1
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if !r.OK || r.Args[0].(int) != x {
t.Fatalf("TestChain_Next")
}
})
x = 2
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if r.OK || r.Args[0].(int) != x {
t.Fatalf("TestChain_Next")
}
})
x = 3
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if !r.OK || i.Context().Value("x").(int) != x {
t.Fatalf("TestChain_Next")
}
})
if i.Context().Value("x").(int) != x*x {
t.Fatalf("TestChain_Next")
}
x = 4 // async call back
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.WithContext("ch", make(chan struct{}))
i.Invoke(func(r Result) {
if !r.OK || i.Context().Value("x").(int) != x {
t.Fatalf("TestChain_Next")
}
})
<-i.Context().Value("ch").(chan struct{})
if i.Context().Value("x").(int) != x*x {
t.Fatalf("TestChain_Next")
}
x = 5
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if r.OK || r.Err == nil {
t.Fatalf("TestChain_Next")
}
})
x = 6
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if !r.OK || r.Err != nil {
t.Fatalf("TestChain_Next")
}
})
x = 7 // async call back
ch = NewChain("test", hs)
i = NewInvocation(context.Background(), ch)
i.WithContext("x", x)
i.Invoke(func(r Result) {
if !r.OK || r.Err != nil {
t.Fatalf("TestChain_Next")
}
})
<-time.After(500 * time.Millisecond)
}