No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

156 líneas
4.8 KiB

  1. // Copyright 2016, Google Inc.
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. package gax
  30. import (
  31. "context"
  32. "errors"
  33. "testing"
  34. "time"
  35. )
  36. var canceledContext context.Context
  37. func init() {
  38. ctx, cancel := context.WithCancel(context.Background())
  39. cancel()
  40. canceledContext = ctx
  41. }
  42. // recordSleeper is a test implementation of sleeper.
  43. type recordSleeper int
  44. func (s *recordSleeper) sleep(ctx context.Context, _ time.Duration) error {
  45. *s++
  46. return ctx.Err()
  47. }
  48. type boolRetryer bool
  49. func (r boolRetryer) Retry(err error) (time.Duration, bool) { return 0, bool(r) }
  50. func TestInvokeSuccess(t *testing.T) {
  51. apiCall := func(context.Context, CallSettings) error { return nil }
  52. var sp recordSleeper
  53. err := invoke(context.Background(), apiCall, CallSettings{}, sp.sleep)
  54. if err != nil {
  55. t.Errorf("found error %s, want nil", err)
  56. }
  57. if sp != 0 {
  58. t.Errorf("slept %d times, should not have slept since the call succeeded", int(sp))
  59. }
  60. }
  61. func TestInvokeNoRetry(t *testing.T) {
  62. apiErr := errors.New("foo error")
  63. apiCall := func(context.Context, CallSettings) error { return apiErr }
  64. var sp recordSleeper
  65. err := invoke(context.Background(), apiCall, CallSettings{}, sp.sleep)
  66. if err != apiErr {
  67. t.Errorf("found error %s, want %s", err, apiErr)
  68. }
  69. if sp != 0 {
  70. t.Errorf("slept %d times, should not have slept since retry is not specified", int(sp))
  71. }
  72. }
  73. func TestInvokeNilRetry(t *testing.T) {
  74. apiErr := errors.New("foo error")
  75. apiCall := func(context.Context, CallSettings) error { return apiErr }
  76. var settings CallSettings
  77. WithRetry(func() Retryer { return nil }).Resolve(&settings)
  78. var sp recordSleeper
  79. err := invoke(context.Background(), apiCall, settings, sp.sleep)
  80. if err != apiErr {
  81. t.Errorf("found error %s, want %s", err, apiErr)
  82. }
  83. if sp != 0 {
  84. t.Errorf("slept %d times, should not have slept since retry is not specified", int(sp))
  85. }
  86. }
  87. func TestInvokeNeverRetry(t *testing.T) {
  88. apiErr := errors.New("foo error")
  89. apiCall := func(context.Context, CallSettings) error { return apiErr }
  90. var settings CallSettings
  91. WithRetry(func() Retryer { return boolRetryer(false) }).Resolve(&settings)
  92. var sp recordSleeper
  93. err := invoke(context.Background(), apiCall, settings, sp.sleep)
  94. if err != apiErr {
  95. t.Errorf("found error %s, want %s", err, apiErr)
  96. }
  97. if sp != 0 {
  98. t.Errorf("slept %d times, should not have slept since retry is not specified", int(sp))
  99. }
  100. }
  101. func TestInvokeRetry(t *testing.T) {
  102. const target = 3
  103. retryNum := 0
  104. apiErr := errors.New("foo error")
  105. apiCall := func(context.Context, CallSettings) error {
  106. retryNum++
  107. if retryNum < target {
  108. return apiErr
  109. }
  110. return nil
  111. }
  112. var settings CallSettings
  113. WithRetry(func() Retryer { return boolRetryer(true) }).Resolve(&settings)
  114. var sp recordSleeper
  115. err := invoke(context.Background(), apiCall, settings, sp.sleep)
  116. if err != nil {
  117. t.Errorf("found error %s, want nil, call should have succeeded after %d tries", err, target)
  118. }
  119. if sp != target-1 {
  120. t.Errorf("retried %d times, want %d", int(sp), int(target-1))
  121. }
  122. }
  123. func TestInvokeRetryTimeout(t *testing.T) {
  124. apiErr := errors.New("foo error")
  125. apiCall := func(context.Context, CallSettings) error { return apiErr }
  126. var settings CallSettings
  127. WithRetry(func() Retryer { return boolRetryer(true) }).Resolve(&settings)
  128. var sp recordSleeper
  129. err := invoke(canceledContext, apiCall, settings, sp.sleep)
  130. if err != context.Canceled {
  131. t.Errorf("found error %s, want %s", err, context.Canceled)
  132. }
  133. }