From 428acae1cbe8bdf3a6a45bcf6826a35f179ef726 Mon Sep 17 00:00:00 2001 From: Joe Bolinger Date: Tue, 13 Aug 2019 08:20:04 -0700 Subject: [PATCH] Add dummy LRO service (#182) --- server/services/operations_service.go | 63 ++++++++++++++- server/services/operations_service_test.go | 91 +++++++++++++++++++--- 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/server/services/operations_service.go b/server/services/operations_service.go index a9500d934..5dce3b65f 100644 --- a/server/services/operations_service.go +++ b/server/services/operations_service.go @@ -17,7 +17,10 @@ package services import ( "context" "encoding/base64" + "math/rand" + "strconv" "strings" + "time" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" @@ -125,18 +128,70 @@ func searchFilterFunc(query string) func(b *pb.Blurb) bool { } } +// CancelOperation returns a successful response if the resource name is not blank func (s operationsServerImpl) CancelOperation(ctx context.Context, in *lropb.CancelOperationRequest) (*empty.Empty, error) { - return nil, status.Error(codes.Unimplemented, "google.longrunning.CancelOperation is unimplemented.") + if in.Name == "" { + return nil, status.Error(codes.NotFound, "cannot cancel operation without a name.") + } + return &empty.Empty{}, nil } +// ListOperations returns a fixed response matching the given PageSize if the resource name is not blank func (s operationsServerImpl) ListOperations(ctx context.Context, in *lropb.ListOperationsRequest) (*lropb.ListOperationsResponse, error) { - return nil, status.Error(codes.Unimplemented, "google.longrunning.ListOperations is unimplemented.") + if in.Name == "" { + return nil, status.Error(codes.NotFound, "cannot list operation without a name.") + } + + var operations []*lropb.Operation + if in.PageSize > 0 { + for i := 1; i <= int(in.PageSize); i++ { + var result *lropb.Operation_Response + if i%2 == 0 { + result = &lropb.Operation_Response{} + } + operations = append(operations, &lropb.Operation{ + Name: "the/thing/" + strconv.Itoa(i), + Done: result != nil, + Result: result, + }) + } + } else { + operations = append(operations, &lropb.Operation{ + Name: "a/pending/thing", + Done: false, + }) + } + + return &lropb.ListOperationsResponse{ + Operations: operations, + NextPageToken: "txenNext", + }, nil } +// DeleteOperation returns a successful response if the resource name is not blank func (s operationsServerImpl) DeleteOperation(ctx context.Context, in *lropb.DeleteOperationRequest) (*empty.Empty, error) { - return nil, status.Error(codes.Unimplemented, "google.longrunning.DeleteOperation is unimplemented.") + if in.Name == "" { + return nil, status.Error(codes.NotFound, "cannot delete operation without a name.") + } + return &empty.Empty{}, nil } +// WaitOperation randomly waits and returns an operation with the same name func (s operationsServerImpl) WaitOperation(ctx context.Context, in *lropb.WaitOperationRequest) (*lropb.Operation, error) { - return nil, status.Error(codes.Unimplemented, "google.longrunning.WaitOperation is unimplemented.") + if in.Name == "" { + return nil, status.Error(codes.NotFound, "cannot wait on a operation without a name.") + } + + num := rand.Intn(500) + time.Sleep(time.Duration(num) * time.Millisecond) + + var result *lropb.Operation_Response + if num%2 == 0 { + result = &lropb.Operation_Response{} + } + return &lropb.Operation{ + Name: in.Name, + Done: result != nil, + Result: result, + }, nil } diff --git a/server/services/operations_service_test.go b/server/services/operations_service_test.go index 95fa7be2e..7f401cac1 100644 --- a/server/services/operations_service_test.go +++ b/server/services/operations_service_test.go @@ -236,36 +236,103 @@ func TestGetOperation_invalidMarshalledProto(t *testing.T) { func TestCancelOperation(t *testing.T) { server := NewOperationsServer(nil) - _, err := server.CancelOperation(context.Background(), nil) + _, err := server.CancelOperation(context.Background(), &lropb.CancelOperationRequest{ + Name: "a/thing", + }) + if err != nil { + t.Error("CancelOperation should have been successful") + } +} + +func TestCancelOperation_notFound(t *testing.T) { + server := NewOperationsServer(nil) + _, err := server.CancelOperation(context.Background(), &lropb.CancelOperationRequest{}) s, _ := status.FromError(err) - if codes.Unimplemented != s.Code() { - t.Errorf("CancelOperation expected code=%d, got %d", codes.Unimplemented, s.Code()) + if codes.NotFound != s.Code() { + t.Errorf("CancelOperation expected code=%d, got %d", codes.NotFound, s.Code()) } } func TestServerListOperation(t *testing.T) { server := NewOperationsServer(nil) - _, err := server.ListOperations(context.Background(), nil) + res, err := server.ListOperations(context.Background(), &lropb.ListOperationsRequest{ + Name: "something", + }) + if err != nil { + t.Error("ListOperations should have been successful") + } + if len(res.Operations) != 1 { + t.Error("ListOperations should have a result") + } + + res, err = server.ListOperations(context.Background(), &lropb.ListOperationsRequest{ + Name: "other", + PageSize: 8, + }) + if err != nil { + t.Error("ListOperations should have been successful") + } + if len(res.Operations) != 8 { + t.Error("ListOperations should have 8 results") + } +} + +func TestServerListOperation_notFound(t *testing.T) { + server := NewOperationsServer(nil) + _, err := server.ListOperations(context.Background(), &lropb.ListOperationsRequest{}) s, _ := status.FromError(err) - if codes.Unimplemented != s.Code() { - t.Errorf("ListOperations expected code=%d, got %d", codes.Unimplemented, s.Code()) + if codes.NotFound != s.Code() { + t.Errorf("ListOperations expected code=%d, got %d", codes.NotFound, s.Code()) } } func TestServerDeleteOperation(t *testing.T) { server := NewOperationsServer(nil) - _, err := server.DeleteOperation(context.Background(), nil) + _, err := server.DeleteOperation(context.Background(), &lropb.DeleteOperationRequest{ + Name: "/delete/the/thing", + }) + if err != nil { + t.Errorf("DeleteOperations should have been successful") + } +} + +func TestServerDeleteOperation_notFound(t *testing.T) { + server := NewOperationsServer(nil) + _, err := server.DeleteOperation(context.Background(), &lropb.DeleteOperationRequest{}) s, _ := status.FromError(err) - if codes.Unimplemented != s.Code() { - t.Errorf("DeleteOperations expected code=%d, got %d", codes.Unimplemented, s.Code()) + if codes.NotFound != s.Code() { + t.Errorf("DeleteOperations expected code=%d, got %d", codes.NotFound, s.Code()) } } func TestServerWaitOperation(t *testing.T) { server := NewOperationsServer(nil) - _, err := server.WaitOperation(context.Background(), nil) + done, notDone := false, false + + for { + res, err := server.WaitOperation(context.Background(), &lropb.WaitOperationRequest{ + Name: "some/op", + }) + if err != nil { + t.Errorf("DeleteOperations should have been successful") + } + + if res.Done { + done = true + } else { + notDone = true + } + if done && notDone { + break + } + } +} + +func TestServerWaitOperation_notFound(t *testing.T) { + server := NewOperationsServer(nil) + _, err := server.WaitOperation(context.Background(), &lropb.WaitOperationRequest{}) s, _ := status.FromError(err) - if codes.Unimplemented != s.Code() { - t.Errorf("DeleteOperations expected code=%d, got %d", codes.Unimplemented, s.Code()) + if codes.NotFound != s.Code() { + t.Errorf("WaitOperations expected code=%d, got %d", codes.NotFound, s.Code()) } }