go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/testmetadata/test_metadata.go (about)

     1  // Copyright 2023 The LUCI Authors.
     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  
    15  // Package testmetadata implements methods to query from TestMetadata spanner table.
    16  package testmetadata
    17  
    18  import (
    19  	"context"
    20  	"time"
    21  
    22  	"cloud.google.com/go/spanner"
    23  	"go.chromium.org/luci/resultdb/internal/spanutil"
    24  	"go.chromium.org/luci/resultdb/pbutil"
    25  	pb "go.chromium.org/luci/resultdb/proto/v1"
    26  	"google.golang.org/protobuf/proto"
    27  )
    28  
    29  // TestMetadataRow represents a row in the TestMetadata table.
    30  type TestMetadataRow struct {
    31  	Project      string
    32  	TestID       string
    33  	RefHash      []byte
    34  	SubRealm     string
    35  	LastUpdated  time.Time
    36  	TestMetadata *pb.TestMetadata
    37  	SourceRef    *pb.SourceRef
    38  	Position     int64
    39  }
    40  
    41  // ReadTestMetadataOptions is the input for the ReadTestMetadata function.
    42  type ReadTestMetadataOptions struct {
    43  	Project   string
    44  	SubRealm  string
    45  	TestIDs   []string
    46  	SourceRef *pb.SourceRef
    47  }
    48  
    49  // ReadTestMetadata read rows from TestMetadata table.
    50  func ReadTestMetadata(ctx context.Context, opts ReadTestMetadataOptions, f func(*TestMetadataRow) error) error {
    51  	st := spanner.NewStatement(`
    52  	SELECT
    53  	 tm.Project,
    54  	 tm.TestId,
    55  	 tm.RefHash,
    56  	 tm.SubRealm,
    57  	 tm.LastUpdated,
    58  	 tm.SourceRef,
    59  	 tm.TestMetadata,
    60  	 tm.Position,
    61  	FROM TestMetadata tm
    62  	WHERE tm.Project = @project
    63  		AND tm.TestId in UNNEST(@testIDs)
    64  		AND tm.RefHash = @refHash
    65  		 AND tm.SubRealm = @subRealm`)
    66  	st.Params = spanutil.ToSpannerMap(map[string]any{
    67  		"project":  opts.Project,
    68  		"testIDs":  opts.TestIDs,
    69  		"refHash":  pbutil.SourceRefHash(opts.SourceRef),
    70  		"subRealm": opts.SubRealm,
    71  	})
    72  	var b spanutil.Buffer
    73  	return spanutil.Query(ctx, st, func(row *spanner.Row) error {
    74  		tmd := &TestMetadataRow{}
    75  		var compressedTestMetadata spanutil.Compressed
    76  		var compressedSourceRef spanutil.Compressed
    77  		if err := b.FromSpanner(row,
    78  			&tmd.Project,
    79  			&tmd.TestID,
    80  			&tmd.RefHash,
    81  			&tmd.SubRealm,
    82  			&tmd.LastUpdated,
    83  			&compressedSourceRef,
    84  			&compressedTestMetadata,
    85  			&tmd.Position); err != nil {
    86  			return err
    87  		}
    88  		tmd.TestMetadata = &pb.TestMetadata{}
    89  		if err := proto.Unmarshal(compressedTestMetadata, tmd.TestMetadata); err != nil {
    90  			return err
    91  		}
    92  		tmd.SourceRef = &pb.SourceRef{}
    93  		if err := proto.Unmarshal(compressedSourceRef, tmd.SourceRef); err != nil {
    94  			return err
    95  		}
    96  		return f(tmd)
    97  	})
    98  }