You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

214 lines
5.1 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package lro supports Long Running Operations for the Google Cloud Libraries.
  15. //
  16. // This package is still experimental and subject to change.
  17. package longrunning
  18. import (
  19. "context"
  20. "errors"
  21. "testing"
  22. "time"
  23. "github.com/golang/protobuf/proto"
  24. "github.com/golang/protobuf/ptypes"
  25. "github.com/golang/protobuf/ptypes/duration"
  26. gax "github.com/googleapis/gax-go/v2"
  27. pb "google.golang.org/genproto/googleapis/longrunning"
  28. status "google.golang.org/genproto/googleapis/rpc/status"
  29. "google.golang.org/grpc"
  30. "google.golang.org/grpc/codes"
  31. )
  32. type getterService struct {
  33. operationsClient
  34. // clock represents the fake current time of the service.
  35. // It is the running sum of the of the duration we have slept.
  36. clock time.Duration
  37. // getTimes records the times at which GetOperation is called.
  38. getTimes []time.Duration
  39. // results are the fake results that GetOperation should return.
  40. results []*pb.Operation
  41. }
  42. func (s *getterService) GetOperation(context.Context, *pb.GetOperationRequest, ...gax.CallOption) (*pb.Operation, error) {
  43. i := len(s.getTimes)
  44. s.getTimes = append(s.getTimes, s.clock)
  45. if i >= len(s.results) {
  46. return nil, errors.New("unexpected call")
  47. }
  48. return s.results[i], nil
  49. }
  50. func (s *getterService) sleeper() sleeper {
  51. return func(_ context.Context, d time.Duration) error {
  52. s.clock += d
  53. return nil
  54. }
  55. }
  56. func TestWait(t *testing.T) {
  57. responseDur := ptypes.DurationProto(42 * time.Second)
  58. responseAny, err := ptypes.MarshalAny(responseDur)
  59. if err != nil {
  60. t.Fatal(err)
  61. }
  62. s := &getterService{
  63. results: []*pb.Operation{
  64. {Name: "foo"},
  65. {Name: "foo"},
  66. {Name: "foo"},
  67. {Name: "foo"},
  68. {Name: "foo"},
  69. {
  70. Name: "foo",
  71. Done: true,
  72. Result: &pb.Operation_Response{
  73. Response: responseAny,
  74. },
  75. },
  76. },
  77. }
  78. op := &Operation{
  79. c: s,
  80. proto: &pb.Operation{Name: "foo"},
  81. }
  82. if op.Done() {
  83. t.Fatal("operation should not have completed yet")
  84. }
  85. var resp duration.Duration
  86. bo := gax.Backoff{
  87. Initial: 1 * time.Second,
  88. Max: 3 * time.Second,
  89. }
  90. if err := op.wait(context.Background(), &resp, &bo, s.sleeper()); err != nil {
  91. t.Fatal(err)
  92. }
  93. if !proto.Equal(&resp, responseDur) {
  94. t.Errorf("response, got %v, want %v", resp, responseDur)
  95. }
  96. if !op.Done() {
  97. t.Errorf("operation should have completed")
  98. }
  99. maxWait := []time.Duration{
  100. 1 * time.Second,
  101. 2 * time.Second,
  102. 3 * time.Second,
  103. 3 * time.Second,
  104. 3 * time.Second,
  105. }
  106. for i := 0; i < len(s.getTimes)-1; i++ {
  107. w := s.getTimes[i+1] - s.getTimes[i]
  108. if mw := maxWait[i]; w > mw {
  109. t.Errorf("backoff, waited %s, max %s", w, mw)
  110. }
  111. }
  112. }
  113. func TestPollRequestError(t *testing.T) {
  114. const opName = "foo"
  115. // All calls error.
  116. s := &getterService{}
  117. op := &Operation{
  118. c: s,
  119. proto: &pb.Operation{Name: opName},
  120. }
  121. if err := op.Poll(context.Background(), nil); err == nil {
  122. t.Fatalf("Poll should error")
  123. }
  124. if n := op.Name(); n != opName {
  125. t.Errorf("operation name, got %q, want %q", n, opName)
  126. }
  127. if op.Done() {
  128. t.Errorf("operation should not have completed; we failed to fetch state")
  129. }
  130. }
  131. func TestPollErrorResult(t *testing.T) {
  132. const (
  133. errCode = codes.NotFound
  134. errMsg = "my error"
  135. )
  136. op := &Operation{
  137. proto: &pb.Operation{
  138. Name: "foo",
  139. Done: true,
  140. Result: &pb.Operation_Error{
  141. Error: &status.Status{
  142. Code: int32(errCode),
  143. Message: errMsg,
  144. },
  145. },
  146. },
  147. }
  148. err := op.Poll(context.Background(), nil)
  149. if got := grpc.Code(err); got != errCode {
  150. t.Errorf("error code, want %s, got %s", errCode, got)
  151. }
  152. if got := grpc.ErrorDesc(err); got != errMsg {
  153. t.Errorf("error code, want %s, got %s", errMsg, got)
  154. }
  155. if !op.Done() {
  156. t.Errorf("operation should have completed")
  157. }
  158. }
  159. type errService struct {
  160. operationsClient
  161. errCancel, errDelete error
  162. }
  163. func (s *errService) CancelOperation(context.Context, *pb.CancelOperationRequest, ...gax.CallOption) error {
  164. return s.errCancel
  165. }
  166. func (s *errService) DeleteOperation(context.Context, *pb.DeleteOperationRequest, ...gax.CallOption) error {
  167. return s.errDelete
  168. }
  169. func TestCancelReturnsError(t *testing.T) {
  170. s := &errService{
  171. errCancel: errors.New("cancel error"),
  172. }
  173. op := &Operation{
  174. c: s,
  175. proto: &pb.Operation{Name: "foo"},
  176. }
  177. if got, want := op.Cancel(context.Background()), s.errCancel; got != want {
  178. t.Errorf("cancel, got error %s, want %s", got, want)
  179. }
  180. }
  181. func TestDeleteReturnsError(t *testing.T) {
  182. s := &errService{
  183. errDelete: errors.New("delete error"),
  184. }
  185. op := &Operation{
  186. c: s,
  187. proto: &pb.Operation{Name: "foo"},
  188. }
  189. if got, want := op.Delete(context.Background()), s.errDelete; got != want {
  190. t.Errorf("cancel, got error %s, want %s", got, want)
  191. }
  192. }