github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/fakes/exec.go (about) 1 package fakes 2 3 import ( 4 "context" 5 "fmt" 6 "sync/atomic" 7 "testing" 8 9 "github.com/bazelbuild/remote-apis-sdks/go/pkg/client" 10 "github.com/bazelbuild/remote-apis-sdks/go/pkg/digest" 11 "google.golang.org/grpc/codes" 12 "google.golang.org/grpc/status" 13 "google.golang.org/protobuf/proto" 14 15 // Redundant imports are required for the google3 mirror. Aliases should not be changed. 16 regrpc "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2" 17 repb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2" 18 oppb "google.golang.org/genproto/googleapis/longrunning" 19 anypb "google.golang.org/protobuf/types/known/anypb" 20 ) 21 22 // Exec implements the complete RE execution interface for a single execution, returning a fixed 23 // result or an error. 24 type Exec struct { 25 // Execution will check the action cache first, and update the action cache upon completion. 26 ac *ActionCache 27 // The action will be fetched from the CAS at start of execution, and outputs will be put in the 28 // CAS upon execution completion. 29 cas *CAS 30 // Fake result of an execution. 31 // The returned completed result, if any. 32 ActionResult *repb.ActionResult 33 // Returned completed execution status, if not Ok. 34 Status *status.Status 35 // Whether action was fake-fetched from the action cache upon execution (simulates a race between 36 // two executions). 37 Cached bool 38 // Any blobs that will be put in the CAS after the fake execution completes. 39 OutputBlobs [][]byte 40 // Name of the logstream to write stdout to. 41 StdOutStreamName string 42 // Name of the logstream to write stderr to. 43 StdErrStreamName string 44 // Number of Execute calls. 45 numExecCalls int32 46 // Used for errors. 47 t testing.TB 48 // The digest of the fake action. 49 adg digest.Digest 50 } 51 52 // NewExec returns a new empty Exec. 53 func NewExec(t testing.TB, ac *ActionCache, cas *CAS) *Exec { 54 c := &Exec{t: t, ac: ac, cas: cas} 55 c.Clear() 56 return c 57 } 58 59 // Clear removes all preset results from the fake. 60 func (s *Exec) Clear() { 61 s.ActionResult = nil 62 s.Status = nil 63 s.Cached = false 64 s.OutputBlobs = nil 65 atomic.StoreInt32(&s.numExecCalls, 0) 66 } 67 68 // ExecuteCalls returns the total number of Execute calls. 69 func (s *Exec) ExecuteCalls() int { 70 return int(atomic.LoadInt32(&s.numExecCalls)) 71 } 72 73 func fakeOPName(adg digest.Digest) string { 74 return "fake-action-" + adg.String() 75 } 76 77 func (s *Exec) fakeExecution(dg digest.Digest, skipCacheLookup bool) (*oppb.Operation, error) { 78 ar := s.ActionResult 79 st := s.Status 80 cached := s.Cached 81 // Check action cache first, unless instructed not to. 82 if !skipCacheLookup { 83 cr := s.ac.Get(dg) 84 if cr != nil { 85 ar = cr 86 st = nil 87 cached = true 88 } 89 } 90 // Fetch action from CAS. 91 blob, ok := s.cas.Get(dg) 92 if !ok { 93 return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("action blob with digest %v not in the cas", dg)) 94 } 95 apb := &repb.Action{} 96 if err := proto.Unmarshal(blob, apb); err != nil { 97 return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("error unmarshalling %v as Action", blob)) 98 } 99 if !apb.DoNotCache { 100 s.ac.Put(dg, ar) 101 } 102 for _, out := range s.OutputBlobs { 103 s.cas.Put(out) 104 } 105 execResp := &repb.ExecuteResponse{ 106 Result: ar, 107 Status: st.Proto(), 108 CachedResult: cached, 109 } 110 any, err := anypb.New(execResp) 111 if err != nil { 112 return nil, err 113 } 114 return &oppb.Operation{ 115 Name: fakeOPName(dg), 116 Done: true, 117 Result: &oppb.Operation_Response{Response: any}, 118 }, nil 119 } 120 121 // GetCapabilities returns the fake capabilities. 122 func (s *Exec) GetCapabilities(ctx context.Context, req *repb.GetCapabilitiesRequest) (res *repb.ServerCapabilities, err error) { 123 dgFn := digest.GetDigestFunction() 124 res = &repb.ServerCapabilities{ 125 ExecutionCapabilities: &repb.ExecutionCapabilities{ 126 DigestFunction: dgFn, 127 ExecEnabled: true, 128 }, 129 CacheCapabilities: &repb.CacheCapabilities{ 130 DigestFunctions: []repb.DigestFunction_Value{dgFn}, 131 ActionCacheUpdateCapabilities: &repb.ActionCacheUpdateCapabilities{ 132 UpdateEnabled: true, 133 }, 134 MaxBatchTotalSizeBytes: client.DefaultMaxBatchSize, 135 SymlinkAbsolutePathStrategy: repb.SymlinkAbsolutePathStrategy_DISALLOWED, 136 }, 137 } 138 return res, nil 139 } 140 141 // Execute returns the saved result ActionResult, or a Status. It also puts it in the action cache 142 // unless the execute request specified 143 func (s *Exec) Execute(req *repb.ExecuteRequest, stream regrpc.Execution_ExecuteServer) (err error) { 144 dg, err := digest.NewFromProto(req.ActionDigest) 145 if err != nil { 146 return status.Error(codes.InvalidArgument, fmt.Sprintf("invalid digest received: %v", req.ActionDigest)) 147 } 148 if dg != s.adg { 149 s.t.Errorf("unexpected action digest received by fake: expected %v, got %v", s.adg, dg) 150 return status.Error(codes.InvalidArgument, fmt.Sprintf("unexpected digest received: %v", req.ActionDigest)) 151 } 152 if s.StdOutStreamName != "" || s.StdErrStreamName != "" { 153 md, err := anypb.New(&repb.ExecuteOperationMetadata{ 154 StdoutStreamName: s.StdOutStreamName, 155 StderrStreamName: s.StdErrStreamName, 156 }) 157 if err != nil { 158 return err 159 } 160 if err := stream.Send(&oppb.Operation{Name: fakeOPName(dg), Metadata: md}); err != nil { 161 return err 162 } 163 } 164 if op, err := s.fakeExecution(dg, req.SkipCacheLookup); err != nil { 165 return err 166 } else if err = stream.Send(op); err != nil { 167 return err 168 } 169 atomic.AddInt32(&s.numExecCalls, 1) 170 return nil 171 } 172 173 func (s *Exec) WaitExecution(req *repb.WaitExecutionRequest, stream regrpc.Execution_WaitExecutionServer) (err error) { 174 if req.Name != fakeOPName(s.adg) { 175 return status.Errorf(codes.NotFound, "requested operation %v not found", req.Name) 176 } 177 if op, err := s.fakeExecution(s.adg, true); err != nil { 178 return err 179 } else { 180 return stream.Send(op) 181 } 182 }