Files
tasks/components/callbacks/statemachine_test.go
Alex ShtinandGitHub 8e8f1b0f7c Remove license header from every file (#7689)
## What changed?
<!-- Describe what has changed in this PR -->
Remove license header from every file. Because it is really hard to
follow in this PR here is the summary:
1. License header is removed from all `.go` and `.proto` files
:fireworks::fireworks:🎆.
2. `LICENSE` file in the root directory has only Temporal and Uber
copyrights.
3. 5 other `LICENSE` files added to the packages which have copyrights
different from Temporal and Uber: Datadog, Xargin, "Mat Ryer, Tyler
Bunnell and contributors".
4. `license_file` flag is removed from all code generation tools.
5. `copyright_file` flag is removed from `go:generate mockgen`
directive.
6. All copyright related targets are removed from `Makefile`.
7. Updated Temporal copyright year to 2025 everywhere.

## Why?
<!-- Tell your future self why have you made these changes -->
I double checked with legal department that it is not needed to have
license header in every file. One file per repo is enough. I put all
copyrights to the root `LICENSE` file and removed header from all other
files. Also updated tools and `Makefile`.
2025-05-01 18:50:21 -07:00

195 lines
5.9 KiB
Go

package callbacks_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
enumsspb "go.temporal.io/server/api/enums/v1"
persistencespb "go.temporal.io/server/api/persistence/v1"
"go.temporal.io/server/common"
"go.temporal.io/server/common/backoff"
"go.temporal.io/server/components/callbacks"
"go.temporal.io/server/service/history/hsm"
)
func TestValidTransitions(t *testing.T) {
// Setup
currentTime := time.Now().UTC()
callback := callbacks.Callback{
&persistencespb.CallbackInfo{
Callback: &persistencespb.Callback{
Variant: &persistencespb.Callback_Nexus_{
Nexus: &persistencespb.Callback_Nexus{
Url: "http://address:666/path/to/callback?query=string",
},
},
},
State: enumsspb.CALLBACK_STATE_SCHEDULED,
},
}
// AttemptFailed
out, err := callbacks.TransitionAttemptFailed.Apply(callback, callbacks.EventAttemptFailed{
Time: currentTime,
Err: fmt.Errorf("test"),
RetryPolicy: backoff.NewExponentialRetryPolicy(time.Second),
})
require.NoError(t, err)
// Assert info object is updated
require.Equal(t, enumsspb.CALLBACK_STATE_BACKING_OFF, callback.State())
require.Equal(t, int32(1), callback.Attempt)
require.Equal(t, "test", callback.LastAttemptFailure.Message)
require.False(t, callback.LastAttemptFailure.GetApplicationFailureInfo().NonRetryable)
require.Equal(t, currentTime, callback.LastAttemptCompleteTime.AsTime())
dt := currentTime.Add(time.Second).Sub(callback.NextAttemptScheduleTime.AsTime())
require.True(t, dt < time.Millisecond*200)
// Assert backoff task is generated
require.Equal(t, 1, len(out.Tasks))
boTask := out.Tasks[0].(callbacks.BackoffTask)
require.Equal(t, callback.NextAttemptScheduleTime.AsTime(), boTask.Deadline())
// Rescheduled
out, err = callbacks.TransitionRescheduled.Apply(callback, callbacks.EventRescheduled{})
require.NoError(t, err)
// Assert info object is updated only where needed
require.Equal(t, enumsspb.CALLBACK_STATE_SCHEDULED, callback.State())
require.Equal(t, int32(1), callback.Attempt)
require.Equal(t, "test", callback.LastAttemptFailure.Message)
// Remains unmodified
require.Equal(t, currentTime, callback.LastAttemptCompleteTime.AsTime())
require.Nil(t, callback.NextAttemptScheduleTime)
// Assert callback task is generated
require.Equal(t, 1, len(out.Tasks))
cbTask := out.Tasks[0].(callbacks.InvocationTask)
require.Equal(t, "http://address:666", cbTask.Destination())
// Store the pre-succeeded state to test Failed later
dup := callbacks.Callback{common.CloneProto(callback.CallbackInfo)}
// Succeeded
currentTime = currentTime.Add(time.Second)
out, err = callbacks.TransitionSucceeded.Apply(callback, callbacks.EventSucceeded{Time: currentTime})
require.NoError(t, err)
// Assert info object is updated only where needed
require.Equal(t, enumsspb.CALLBACK_STATE_SUCCEEDED, callback.State())
require.Equal(t, int32(2), callback.Attempt)
require.Nil(t, callback.LastAttemptFailure)
require.Equal(t, currentTime, callback.LastAttemptCompleteTime.AsTime())
require.Nil(t, callback.NextAttemptScheduleTime)
// Assert no additional tasks are generated
require.Equal(t, 0, len(out.Tasks))
// Reset back to scheduled
callback = dup
// Increment the time to ensure it's updated in the transition
currentTime = currentTime.Add(time.Second)
// failed
out, err = callbacks.TransitionFailed.Apply(callback, callbacks.EventFailed{Time: currentTime, Err: fmt.Errorf("failed")})
require.NoError(t, err)
// Assert info object is updated only where needed
require.Equal(t, enumsspb.CALLBACK_STATE_FAILED, callback.State())
require.Equal(t, int32(2), callback.Attempt)
require.Equal(t, "failed", callback.LastAttemptFailure.Message)
require.True(t, callback.LastAttemptFailure.GetApplicationFailureInfo().NonRetryable)
require.Equal(t, currentTime, callback.LastAttemptCompleteTime.AsTime())
require.Nil(t, callback.NextAttemptScheduleTime)
// Assert no additional tasks are generated
require.Equal(t, 0, len(out.Tasks))
}
func TestCompareState(t *testing.T) {
reg := hsm.NewRegistry()
require.NoError(t, callbacks.RegisterStateMachine(reg))
def, ok := reg.Machine(callbacks.StateMachineType)
require.True(t, ok)
cases := []struct {
name string
s1, s2 enumsspb.CallbackState
attempts1, attempts2 int32
sign int
expectError bool
}{
{
name: "standby < scheduled",
s1: enumsspb.CALLBACK_STATE_STANDBY,
s2: enumsspb.CALLBACK_STATE_SCHEDULED,
sign: -1,
},
{
name: "scheduled = scheduled",
s1: enumsspb.CALLBACK_STATE_SCHEDULED,
s2: enumsspb.CALLBACK_STATE_SCHEDULED,
attempts1: 2,
attempts2: 2,
sign: 0,
},
{
name: "succeeded not comparable to failed",
s1: enumsspb.CALLBACK_STATE_SUCCEEDED,
s2: enumsspb.CALLBACK_STATE_FAILED,
expectError: true,
},
{
name: "backing off < failed",
s1: enumsspb.CALLBACK_STATE_BACKING_OFF,
s2: enumsspb.CALLBACK_STATE_FAILED,
sign: -1,
},
{
name: "scheduled > backing off",
s1: enumsspb.CALLBACK_STATE_SCHEDULED,
s2: enumsspb.CALLBACK_STATE_BACKING_OFF,
sign: 1,
},
{
name: "backing off < scheduled with greater attempt",
s1: enumsspb.CALLBACK_STATE_BACKING_OFF,
s2: enumsspb.CALLBACK_STATE_SCHEDULED,
attempts2: 1,
sign: -1,
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
s1 := callbacks.Callback{
CallbackInfo: &persistencespb.CallbackInfo{
State: tc.s1,
Attempt: tc.attempts1,
},
}
s2 := callbacks.Callback{
CallbackInfo: &persistencespb.CallbackInfo{
State: tc.s2,
Attempt: tc.attempts2,
},
}
res, err := def.CompareState(s1, s2)
if tc.expectError {
require.Error(t, err)
return
}
require.NoError(t, err)
if tc.sign == 0 {
require.Equal(t, 0, res)
} else if tc.sign > 0 {
require.Greater(t, res, 0)
} else {
require.Greater(t, 0, res)
}
})
}
}