| // Copyright 2025 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the \"License\"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an \"AS IS\" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package rsmsg |
| |
| import ( |
| "bytes" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| "google.golang.org/protobuf/testing/protocmp" |
| |
| rspb "google.golang.org/genproto/googleapis/devtools/resultstore/v2" |
| |
| _ "github.com/bazelbuild/rsclient/internal/pkg/testsetup" |
| ) |
| |
| // TestUploadRequestsReadWrite verifies that a slice of UploadRequests can be correctly |
| // serialized to a byte slice and deserialized back. |
| func TestUploadRequestsReadWrite(t *testing.T) { |
| tests := []struct { |
| name string |
| requests []*rspb.UploadRequest |
| }{ |
| { |
| name: "empty-requests", |
| requests: []*rspb.UploadRequest{}, |
| }, |
| { |
| name: "one-blank-request", |
| requests: []*rspb.UploadRequest{ |
| {}, |
| }, |
| }, |
| { |
| name: "create-invocation-only", |
| requests: []*rspb.UploadRequest{ |
| NewInvocationUploadRequest(rspb.UploadRequest_CREATE, NewInvocation("", StatusUnspecified)), |
| }, |
| }, |
| { |
| name: "create-and-finalize-invocation", |
| requests: []*rspb.UploadRequest{ |
| NewInvocationUploadRequest(rspb.UploadRequest_CREATE, NewInvocation("", StatusUnspecified)), |
| NewInvocationUploadRequest(rspb.UploadRequest_FINALIZE, NewInvocation("", StatusUnspecified)), |
| }, |
| }, |
| } |
| for _, test := range tests { |
| wireData, err := UploadRequestsToBytes(test.requests) |
| |
| if err != nil { |
| t.Fatalf("For test %q, failed to UploadRequestsToBytes: %v", test.name, err) |
| } |
| |
| gotReqs, err := BytesToUploadRequests(t.Context(), wireData) |
| if err != nil { |
| t.Fatalf("For test %q, failed to BytesToUploadRequests: %v", test.name, err) |
| } |
| |
| // compare requests against original |
| if diff := cmp.Diff(test.requests, gotReqs, protocmp.Transform()); diff != "" { |
| t.Errorf("For test %q, found unexpected differences in UploadRequests (-want +got):\n%s", test.name, diff) |
| } |
| } |
| } |
| |
| // TestSingleUploadRequestReadWrite verifies that a single UploadRequest can be correctly |
| // written to and read back from an io.Writer/io.Reader. |
| func TestSingleUploadRequestReadWrite(t *testing.T) { |
| originalReq := NewInvocationUploadRequest(rspb.UploadRequest_CREATE, func() *rspb.Invocation { |
| inv := NewInvocation("test-invocation-id", StatusUnspecified) |
| inv.InvocationAttributes = &rspb.InvocationAttributes{ProjectId: "test-project"} |
| return inv |
| }()) |
| |
| var buf bytes.Buffer |
| |
| // Write the original request to the buffer. |
| if err := WriteUploadRequest(&buf, originalReq); err != nil { |
| t.Fatalf("WriteUploadRequest() failed: %v", err) |
| } |
| |
| // Read the request back from the buffer. |
| readReq, err := ReadUploadRequest(&buf) |
| if err != nil { |
| t.Fatalf("ReadUploadRequest() failed: %v", err) |
| } |
| |
| // Verify that the original and read-back requests are identical. |
| if diff := cmp.Diff(originalReq, readReq, protocmp.Transform()); diff != "" { |
| t.Errorf("Read/Write mismatch (-want +got):\n%s", diff) |
| } |
| |
| // Ensure no extra data is left in the buffer. |
| if buf.Len() != 0 { |
| t.Errorf("Expected buffer to be empty after read, but %d bytes remain.", buf.Len()) |
| } |
| } |
| |
| // TestReadUploadRequest_Errors verifies that ReadUploadRequest returns an error for malformed input. |
| func TestReadUploadRequest_Errors(t *testing.T) { |
| t.Run("EmptyReader", func(t *testing.T) { |
| var buf bytes.Buffer |
| _, err := ReadUploadRequest(&buf) |
| if err == nil { |
| t.Error("Expected error for empty reader, got nil") |
| } |
| }) |
| |
| t.Run("ShortLength", func(t *testing.T) { |
| // Only 2 bytes instead of 4 for the length |
| buf := bytes.NewBuffer([]byte{0x01, 0x00}) |
| _, err := ReadUploadRequest(buf) |
| if err == nil { |
| t.Error("Expected error for short length prefix, got nil") |
| } |
| }) |
| |
| t.Run("ShortPayload", func(t *testing.T) { |
| // Length prefix says 10 bytes, but only 2 follow |
| buf := bytes.NewBuffer([]byte{0x0A, 0x00, 0x00, 0x00, 0x01, 0x02}) |
| _, err := ReadUploadRequest(buf) |
| if err == nil { |
| t.Error("Expected error for short payload, got nil") |
| } |
| }) |
| } |