Files
2026-07-13 12:49:10 +08:00

135 lines
3.8 KiB
Go

/*
* Copyright 2026 CloudWeGo Authors
*
* 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 tool
import (
"context"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/cloudwego/eino/internal/core"
)
func TestInterrupt(t *testing.T) {
ctx := context.Background()
t.Run("basic interrupt", func(t *testing.T) {
err := Interrupt(ctx, "test info")
assert.Error(t, err)
var signal *core.InterruptSignal
assert.True(t, errors.As(err, &signal))
assert.Equal(t, "test info", signal.Info)
assert.True(t, signal.IsRootCause)
})
}
func TestStatefulInterrupt(t *testing.T) {
ctx := context.Background()
t.Run("stateful interrupt", func(t *testing.T) {
type myState struct {
Value int
}
state := &myState{Value: 42}
err := StatefulInterrupt(ctx, "test info", state)
assert.Error(t, err)
var signal *core.InterruptSignal
assert.True(t, errors.As(err, &signal))
assert.Equal(t, "test info", signal.Info)
assert.Equal(t, state, signal.State)
assert.True(t, signal.IsRootCause)
})
}
func TestCompositeInterrupt(t *testing.T) {
ctx := context.Background()
t.Run("no sub errors falls back to StatefulInterrupt", func(t *testing.T) {
err := CompositeInterrupt(ctx, "composite info", "my state")
assert.Error(t, err)
var signal *core.InterruptSignal
assert.True(t, errors.As(err, &signal))
assert.Equal(t, "composite info", signal.Info)
assert.Equal(t, "my state", signal.State)
assert.True(t, signal.IsRootCause)
assert.Empty(t, signal.Subs)
})
t.Run("with InterruptSignal sub error", func(t *testing.T) {
subSignal, _ := core.Interrupt(ctx, "sub info", "sub state", nil)
err := CompositeInterrupt(ctx, "composite info", "my state", subSignal)
assert.Error(t, err)
var signal *core.InterruptSignal
assert.True(t, errors.As(err, &signal))
assert.Equal(t, "composite info", signal.Info)
assert.Equal(t, "my state", signal.State)
assert.Len(t, signal.Subs, 1)
assert.Equal(t, "sub info", signal.Subs[0].Info)
})
t.Run("with non-interrupt error returns error", func(t *testing.T) {
nonInterruptErr := errors.New("regular error")
err := CompositeInterrupt(ctx, "composite info", "my state", nonInterruptErr)
assert.Error(t, err)
assert.Contains(t, err.Error(), "composite interrupt but one of the sub error is not interrupt error")
var signal *core.InterruptSignal
assert.False(t, errors.As(err, &signal))
})
t.Run("with multiple sub errors", func(t *testing.T) {
subSignal1, _ := core.Interrupt(ctx, "sub1 info", nil, nil)
subSignal2, _ := core.Interrupt(ctx, "sub2 info", nil, nil)
err := CompositeInterrupt(ctx, "composite info", nil, subSignal1, subSignal2)
assert.Error(t, err)
var signal *core.InterruptSignal
assert.True(t, errors.As(err, &signal))
assert.Len(t, signal.Subs, 2)
})
}
func TestGetInterruptState(t *testing.T) {
t.Run("not interrupted returns false", func(t *testing.T) {
ctx := context.Background()
wasInterrupted, hasState, state := GetInterruptState[string](ctx)
assert.False(t, wasInterrupted)
assert.False(t, hasState)
assert.Empty(t, state)
})
}
func TestGetResumeContext(t *testing.T) {
t.Run("not resume target returns false", func(t *testing.T) {
ctx := context.Background()
isResumeTarget, hasData, data := GetResumeContext[string](ctx)
assert.False(t, isResumeTarget)
assert.False(t, hasData)
assert.Empty(t, data)
})
}