go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/clustering/chunkstore/fake.go (about) 1 // Copyright 2022 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 chunkstore 16 17 import ( 18 "context" 19 "fmt" 20 21 "google.golang.org/protobuf/proto" 22 23 "go.chromium.org/luci/common/errors" 24 25 cpb "go.chromium.org/luci/analysis/internal/clustering/proto" 26 "go.chromium.org/luci/analysis/pbutil" 27 ) 28 29 // FakeClient provides a fake implementation of a chunk store, for testing. 30 // Chunks are stored in-memory. 31 type FakeClient struct { 32 // Contents are the chunk stored in the store, by their file name. 33 // File names can be obtained using the FileName method. 34 Contents map[string]*cpb.Chunk 35 36 // A callback function to be called during Get(...). This allows 37 // the test to change the environment during the processing of 38 // a particular chunk. 39 GetCallack func(objectID string) 40 } 41 42 // NewFakeClient initialises a new FakeClient. 43 func NewFakeClient() *FakeClient { 44 return &FakeClient{ 45 Contents: make(map[string]*cpb.Chunk), 46 } 47 } 48 49 // Put saves the given chunk to storage. If successful, it returns 50 // the randomly-assigned ID of the created object. 51 func (fc *FakeClient) Put(ctx context.Context, project string, content *cpb.Chunk) (string, error) { 52 if err := pbutil.ValidateProject(project); err != nil { 53 return "", err 54 } 55 _, err := proto.Marshal(content) 56 if err != nil { 57 return "", errors.Annotate(err, "marhsalling chunk").Err() 58 } 59 objID, err := generateObjectID() 60 if err != nil { 61 return "", err 62 } 63 name := FileName(project, objID) 64 if _, ok := fc.Contents[name]; ok { 65 // Indicates a test with poorly seeded randomness. 66 return "", errors.New("file already exists") 67 } 68 fc.Contents[name] = proto.Clone(content).(*cpb.Chunk) 69 return objID, nil 70 } 71 72 // Get retrieves the chunk with the specified object ID and returns it. 73 func (fc *FakeClient) Get(ctx context.Context, project, objectID string) (*cpb.Chunk, error) { 74 if err := pbutil.ValidateProject(project); err != nil { 75 return nil, err 76 } 77 if err := validateObjectID(objectID); err != nil { 78 return nil, err 79 } 80 name := FileName(project, objectID) 81 content, ok := fc.Contents[name] 82 if !ok { 83 return nil, fmt.Errorf("blob does not exist: %q", name) 84 } 85 if fc.GetCallack != nil { 86 fc.GetCallack(objectID) 87 } 88 return proto.Clone(content).(*cpb.Chunk), nil 89 }