go.fuchsia.dev/infra@v0.0.0-20240507153436-9b593402251b/cmd/artifacts/common_test.go (about)

     1  // Copyright 2019 The Fuchsia Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"reflect"
    10  	"testing"
    11  
    12  	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
    13  	"google.golang.org/genproto/protobuf/field_mask"
    14  	"google.golang.org/grpc"
    15  	"google.golang.org/protobuf/types/known/structpb"
    16  )
    17  
    18  func TestGetStorageBucket(t *testing.T) {
    19  	tests := []struct {
    20  		// The name of this test case.
    21  		name string
    22  
    23  		// The ID of the build to query.
    24  		input string
    25  
    26  		// A mock RPC response from the BuildBucket service.
    27  		mock mockBuildsClient
    28  		// mock *buildbucketpb.Build
    29  
    30  		// The expected GetBuildRequest.
    31  		expectedRequest *buildbucketpb.GetBuildRequest
    32  
    33  		// The expected output Cloud Storage bucket.
    34  		expectedBucket string
    35  
    36  		// Whether to expect an error.
    37  		expectErr bool
    38  	}{
    39  		{
    40  			name:           "should return the storage bucket read from a build's properties",
    41  			input:          "123",
    42  			expectedBucket: "the_bucket",
    43  			expectedRequest: &buildbucketpb.GetBuildRequest{
    44  				Id: 123,
    45  				Fields: &field_mask.FieldMask{
    46  					Paths: []string{"output"},
    47  				},
    48  			},
    49  			mock: mockBuildsClient{
    50  				response: &buildbucketpb.Build{
    51  					Id: 123,
    52  					Output: &buildbucketpb.Build_Output{
    53  						Properties: &structpb.Struct{
    54  							Fields: map[string]*structpb.Value{
    55  								"artifact_gcs_bucket": {
    56  									Kind: &structpb.Value_StringValue{
    57  										StringValue: "the_bucket",
    58  									},
    59  								},
    60  							},
    61  						},
    62  					},
    63  				},
    64  			},
    65  		}, {
    66  			name:           "should return default bucket if no build is returned",
    67  			input:          "123",
    68  			expectedBucket: defaultStorageBucket,
    69  			expectedRequest: &buildbucketpb.GetBuildRequest{
    70  				Id: 123,
    71  				Fields: &field_mask.FieldMask{
    72  					Paths: []string{"output"},
    73  				},
    74  			},
    75  			mock: mockBuildsClient{
    76  				response: nil,
    77  			},
    78  		}, {
    79  			name:           "should return default bucket if the RPC fails",
    80  			input:          "123",
    81  			expectedBucket: defaultStorageBucket,
    82  			expectedRequest: &buildbucketpb.GetBuildRequest{
    83  				Id: 123,
    84  				Fields: &field_mask.FieldMask{
    85  					Paths: []string{"output"},
    86  				},
    87  			},
    88  			mock: mockBuildsClient{
    89  				shouldErr: true,
    90  				response: &buildbucketpb.Build{
    91  					Id: 123,
    92  					Output: &buildbucketpb.Build_Output{
    93  						Properties: &structpb.Struct{
    94  							Fields: map[string]*structpb.Value{},
    95  						},
    96  					},
    97  				},
    98  			},
    99  		}, {
   100  			name:      "should err if no property describing the storage bucket is found",
   101  			input:     "123",
   102  			expectErr: true,
   103  			expectedRequest: &buildbucketpb.GetBuildRequest{
   104  				Id: 123,
   105  				Fields: &field_mask.FieldMask{
   106  					Paths: []string{"output"},
   107  				},
   108  			},
   109  			mock: mockBuildsClient{
   110  				response: &buildbucketpb.Build{
   111  					Id: 123,
   112  					Output: &buildbucketpb.Build_Output{
   113  						Properties: &structpb.Struct{
   114  							Fields: map[string]*structpb.Value{},
   115  						},
   116  					},
   117  				},
   118  			},
   119  		},
   120  	}
   121  
   122  	for _, tt := range tests {
   123  		t.Run(tt.name, func(t *testing.T) {
   124  			bucket, err := getStorageBucket(context.Background(), &tt.mock, tt.input)
   125  			if err != nil != tt.expectErr {
   126  				if err == nil {
   127  					t.Error("wanted an error but got nil")
   128  				} else {
   129  					t.Errorf("unexpected error: %s", err)
   130  				}
   131  			}
   132  
   133  			compare := func(kind string, expected, actual any) {
   134  				if !reflect.DeepEqual(expected, actual) {
   135  					t.Errorf("expected %s:\n%+v\nbut got:\n%+v", kind, expected, actual)
   136  				}
   137  			}
   138  
   139  			compare("SearchBuildsRequest", tt.expectedRequest, tt.mock.request)
   140  			compare("Storage bucket", tt.expectedBucket, bucket)
   141  		})
   142  	}
   143  }
   144  
   145  type mockBuildsClient struct {
   146  	shouldErr bool
   147  	response  *buildbucketpb.Build
   148  	request   *buildbucketpb.GetBuildRequest
   149  }
   150  
   151  func (mock *mockBuildsClient) GetBuild(ctx context.Context, req *buildbucketpb.GetBuildRequest, _ ...grpc.CallOption) (*buildbucketpb.Build, error) {
   152  	mock.request = req
   153  	if mock.shouldErr {
   154  		return nil, errors.New("no builds found")
   155  	}
   156  
   157  	return mock.response, nil
   158  }