options_test.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package retry
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. "time"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/tal-tech/go-zero/core/logx"
  9. "google.golang.org/grpc"
  10. "google.golang.org/grpc/codes"
  11. "google.golang.org/grpc/metadata"
  12. "google.golang.org/grpc/status"
  13. )
  14. func TestRetryWithDisable(t *testing.T) {
  15. opt := &options{}
  16. assert.EqualValues(t, &options{}, parseRetryCallOptions(opt, WithDisable()))
  17. }
  18. func TestRetryWithMax(t *testing.T) {
  19. n := 5
  20. for i := 0; i < n; i++ {
  21. opt := &options{}
  22. assert.EqualValues(t, &options{max: i}, parseRetryCallOptions(opt, WithMax(i)))
  23. }
  24. }
  25. func TestRetryWithBackoff(t *testing.T) {
  26. opt := &options{}
  27. retryCallOptions := parseRetryCallOptions(opt, WithBackoff(func(attempt int) time.Duration {
  28. return time.Millisecond
  29. }))
  30. assert.EqualValues(t, time.Millisecond, retryCallOptions.backoffFunc(1))
  31. }
  32. func TestRetryWithCodes(t *testing.T) {
  33. opt := &options{}
  34. c := []codes.Code{codes.Unknown, codes.NotFound}
  35. options := parseRetryCallOptions(opt, WithCodes(c...))
  36. assert.EqualValues(t, c, options.codes)
  37. }
  38. func TestRetryWithPerRetryTimeout(t *testing.T) {
  39. opt := &options{}
  40. options := parseRetryCallOptions(opt, WithPerRetryTimeout(time.Millisecond))
  41. assert.EqualValues(t, time.Millisecond, options.perCallTimeout)
  42. }
  43. func Test_waitRetryBackoff(t *testing.T) {
  44. logx.Disable()
  45. opt := &options{perCallTimeout: time.Second, backoffFunc: func(attempt int) time.Duration {
  46. return time.Second
  47. }}
  48. logger := logx.WithContext(context.Background())
  49. err := waitRetryBackoff(logger, 1, context.Background(), opt)
  50. assert.NoError(t, err)
  51. ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond)
  52. defer cancelFunc()
  53. err = waitRetryBackoff(logger, 1, ctx, opt)
  54. assert.ErrorIs(t, err, status.FromContextError(context.DeadlineExceeded).Err())
  55. }
  56. func Test_isRetriable(t *testing.T) {
  57. assert.False(t, isRetriable(status.FromContextError(context.DeadlineExceeded).Err(), &options{codes: DefaultRetriableCodes}))
  58. assert.True(t, isRetriable(status.Error(codes.ResourceExhausted, ""), &options{codes: DefaultRetriableCodes}))
  59. assert.False(t, isRetriable(errors.New("error"), &options{}))
  60. }
  61. func Test_perCallContext(t *testing.T) {
  62. opt := &options{perCallTimeout: time.Second, includeRetryHeader: true}
  63. ctx := metadata.NewIncomingContext(context.Background(), map[string][]string{"1": {"1"}})
  64. callContext := perCallContext(ctx, opt, 1)
  65. md, ok := metadata.FromOutgoingContext(callContext)
  66. assert.True(t, ok)
  67. assert.EqualValues(t, metadata.MD{"1": {"1"}, AttemptMetadataKey: {"1"}}, md)
  68. }
  69. func Test_filterCallOptions(t *testing.T) {
  70. grpcEmptyCallOpt := &grpc.EmptyCallOption{}
  71. retryCallOpt := &CallOption{}
  72. options, retryCallOptions := filterCallOptions([]grpc.CallOption{
  73. grpcEmptyCallOpt,
  74. retryCallOpt,
  75. })
  76. assert.EqualValues(t, []grpc.CallOption{grpcEmptyCallOpt}, options)
  77. assert.EqualValues(t, []*CallOption{retryCallOpt}, retryCallOptions)
  78. }