Skip to content

Commit

Permalink
fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
sysulq committed Jan 13, 2025
1 parent df52d83 commit 0920665
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 48 deletions.
51 changes: 47 additions & 4 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,16 @@ func Example_openTelemetryTrace() {
otel.SetTracerProvider(tracerProvider)

kod.Run(context.Background(), func(ctx context.Context, app *helloworld.App) error {
kod.FromContext(ctx).SetInterceptors(ktrace.Interceptor())

ctx, span := app.Tracer().Start(ctx, "example")
defer span.End()
app.L(ctx).Info("Hello, World!")
app.L(ctx).WarnContext(ctx, "Hello, World!")

app.HelloWorld.Get().SayHello(ctx)
return nil
}, kod.WithInterceptors(ktrace.Interceptor()))
})

fmt.Println(observer.Filter(func(m map[string]any) bool {
return m["trace_id"] != nil && m["span_id"] != nil
Expand Down Expand Up @@ -184,17 +186,19 @@ func Example_openTelemetryMetric() {

// This example demonstrates how to use [kod.WithInterceptors] to provide global interceptors to the application.
func Example_interceptorGlobal() {
interceptor := interceptor.Interceptor(func(ctx context.Context, info interceptor.CallInfo, req, res []interface{}, next interceptor.HandleFunc) error {
itcpt := interceptor.Interceptor(func(ctx context.Context, info interceptor.CallInfo, req, res []interface{}, next interceptor.HandleFunc) error {
fmt.Println("Before call")
err := next(ctx, info, req, res)
fmt.Println("After call")
return err
})

kod.Run(context.Background(), func(ctx context.Context, app *helloworld.App) error {
kod.FromContext(ctx).SetInterceptors(itcpt)

app.HelloWorld.Get().SayHello(ctx)
return nil
}, kod.WithInterceptors(interceptor))
})
// Output:
// helloWorld init
// Before call
Expand All @@ -221,9 +225,13 @@ func Example_interceptorComponent() {
// Such as [krecovery.Interceptor], [ktrace.Interceptor], and [kmetric.Interceptor] ...
func Example_interceptorBuiltin() {
kod.Run(context.Background(), func(ctx context.Context, app *helloworld.App) error {
kod.FromContext(ctx).SetInterceptors(interceptor.Chain([]interceptor.Interceptor{
krecovery.Interceptor(), ktrace.Interceptor(), kmetric.Interceptor(),
}))

app.HelloWorld.Get().SayHello(ctx)
return nil
}, kod.WithInterceptors(krecovery.Interceptor(), ktrace.Interceptor(), kmetric.Interceptor()))
})
// Output:
// helloWorld init
// Hello, World!
Expand Down Expand Up @@ -341,3 +349,38 @@ func Example_testWithDefer() {
// Defer called
// helloWorld shutdown
}

// This example demonstrates how to use [in
// Example_testDynamicInterceptor demonstrates how to use dynamic interceptors in kod.
// It shows:
// 1. How to create a custom interceptor function that executes before and after method calls
// 2. How to set a default interceptor using interceptor.SetDefault
// 3. The difference between intercepted and non-intercepted method calls
//
// The example makes two calls to SayHello:
// - First call executes normally without interception
// - Second call is wrapped by the interceptor which prints "Before call" and "After call"
func Example_testDynamicInterceptor() {
kod.Run(context.Background(), func(ctx context.Context, app *helloworld.App) error {
itcpt := func(ctx context.Context, info interceptor.CallInfo, req, res []interface{}, next interceptor.HandleFunc) error {
fmt.Println("Before call")
err := next(ctx, info, req, res)
fmt.Println("After call")
return err
}

app.HelloWorld.Get().SayHello(ctx)

kod.FromContext(ctx).SetInterceptors(itcpt)

app.HelloWorld.Get().SayHello(ctx)
return nil
})
// Output:
// helloWorld init
// Hello, World!
// Before call
// Hello, World!
// After call
// helloWorld shutdown
}
31 changes: 2 additions & 29 deletions interceptor/interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package interceptor

import (
"context"
"sync/atomic"

"github.com/go-kod/kod/internal/singleton"
)
Expand All @@ -24,13 +23,8 @@ type Interceptor func(ctx context.Context, info CallInfo, req, reply []any, invo
// Condition is the type of the function used to determine whether an interceptor should be used.
type Condition func(ctx context.Context, info CallInfo) bool

var (
// pool is a singleton for interceptors.
pool = singleton.New[Interceptor]()

// defaultInterceptor is the default interceptor.
defaultInterceptor atomic.Pointer[Interceptor]
)
// pool is a singleton for interceptors.
var pool = singleton.New[Interceptor]()

// SingletonByFullMethod returns an Interceptor that is a singleton for the given method.
func SingletonByFullMethod(initFn func() Interceptor) Interceptor {
Expand All @@ -41,27 +35,6 @@ func SingletonByFullMethod(initFn func() Interceptor) Interceptor {
}
}

func init() {
defaultInterceptor.Store(new(Interceptor))
}

// Default returns the default interceptor dynamically.
func Default() Interceptor {
return func(ctx context.Context, info CallInfo, req, reply []any, invoker HandleFunc) error {
defaultInterceptor := *defaultInterceptor.Load()
if defaultInterceptor == nil {
return invoker(ctx, info, req, reply)
}

return defaultInterceptor(ctx, info, req, reply, invoker)
}
}

// SetDefault sets the default interceptor.
func SetDefault(interceptor Interceptor) {
defaultInterceptor.Store(&interceptor)
}

// Chain converts a slice of Interceptors into a single Interceptor.
func Chain(interceptors []Interceptor) Interceptor {
if len(interceptors) == 0 {
Expand Down
20 changes: 7 additions & 13 deletions kod.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,6 @@ func WithRegistrations(regs ...*Registration) func(*options) {
}
}

// WithInterceptors is an option setter for specifying interceptors.
func WithInterceptors(interceptors ...interceptor.Interceptor) func(*options) {
return func(opts *options) {
opts.interceptors = interceptors
}
}

// WithKoanf is an option setter for specifying a custom Koanf instance.
func WithKoanf(cfg *koanf.Koanf) func(*options) {
return func(opts *options) {
Expand Down Expand Up @@ -320,6 +313,8 @@ type Kod struct {

hooker *hooks.Hooker

interceptor interceptor.Interceptor

regs []*Registration
registryByName map[string]*Registration
registryByInterface map[reflect.Type]*Registration
Expand All @@ -335,7 +330,6 @@ type options struct {
configFilename string
fakes map[reflect.Type]any
registrations []*Registration
interceptors []interceptor.Interceptor
koanf *koanf.Koanf
}

Expand Down Expand Up @@ -369,11 +363,6 @@ func newKod(_ context.Context, opts ...func(*options)) (*Kod, error) {
return nil, err
}

// Set the default interceptors.
if len(kod.opts.interceptors) > 0 {
interceptor.SetDefault(interceptor.Chain(kod.opts.interceptors))
}

kod.lazyInitComponents, err = processRegistrations(kod.regs)
if err != nil {
return nil, err
Expand All @@ -391,6 +380,11 @@ func (k *Kod) Config() kodConfig {
return k.config
}

// SetDefaultInterceptor sets the default interceptor for the Kod instance.
func (k *Kod) SetInterceptors(interceptors ...interceptor.Interceptor) {
k.interceptor = interceptor.Chain(interceptors)
}

// Defer adds a hook function to the Kod instance.
func (k *Kod) Defer(name string, fn func(context.Context) error) {
k.hooker.Add(hooks.HookFunc{Name: name, Fn: fn})
Expand Down
9 changes: 8 additions & 1 deletion registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ func (k *Kod) getIntf(ctx context.Context, t reflect.Type) (any, error) {
return nil, err
}

itcpt := interceptor.Default()
itcpt := func(ctx context.Context, info interceptor.CallInfo, req, reply []any, invoker interceptor.HandleFunc) error {
if k.interceptor == nil {
return invoker(ctx, info, req, reply)
}

return k.interceptor(ctx, info, req, reply, invoker)
}

if h, ok := impl.(interface {
Interceptors() []interceptor.Interceptor
}); ok {
Expand Down
4 changes: 3 additions & 1 deletion tests/case1/panic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ func TestRunWithInterceptor(t *testing.T) {

t.Run("panicNoRecvoeryCase with interceptor", func(t *testing.T) {
kod.RunTest(t, func(ctx context.Context, t panicNoRecvoeryCaseInterface) {
kod.FromContext(ctx).SetInterceptors(krecovery.Interceptor())

t.TestPanic(ctx)
}, kod.WithInterceptors(krecovery.Interceptor()))
})
})
}

0 comments on commit 0920665

Please sign in to comment.