go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/casviewer/blobs_test.go (about) 1 // Copyright 2020 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 casviewer 16 17 import ( 18 "context" 19 "io" 20 "net/http/httptest" 21 "testing" 22 23 "github.com/bazelbuild/remote-apis-sdks/go/pkg/client" 24 "github.com/bazelbuild/remote-apis-sdks/go/pkg/digest" 25 "github.com/bazelbuild/remote-apis-sdks/go/pkg/fakes" 26 repb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2" 27 . "github.com/smartystreets/goconvey/convey" 28 "google.golang.org/grpc/codes" 29 "google.golang.org/protobuf/proto" 30 31 "go.chromium.org/luci/grpc/grpcutil" 32 "go.chromium.org/luci/server/templates" 33 ) 34 35 func TestBlobs(t *testing.T) { 36 t.Parallel() 37 38 ctx := context.Background() 39 ctx = templates.Use(ctx, getTemplateBundle("test-version-1"), nil) 40 41 w := httptest.NewRecorder() 42 43 Convey("renderTree", t, func() { 44 cl := fakeClient(ctx, t) 45 46 Convey("Not Found", func() { 47 // This blob doesn't exist on CAS. 48 bd := digest.NewFromBlob([]byte{1}) 49 50 err := renderTree(ctx, w, cl, &bd, testInstance) 51 52 So(grpcutil.Code(err), ShouldEqual, codes.NotFound) 53 So(w.Body.String(), ShouldEqual, "") 54 }) 55 56 Convey("Must be Directory", func() { 57 // This blob exists on CAS, but isn't a Directory. 58 bd, err := cl.WriteBlob(context.Background(), []byte{1}) 59 So(err, ShouldBeNil) 60 61 err = renderTree(ctx, w, cl, &bd, testInstance) 62 63 So(grpcutil.Code(err), ShouldEqual, codes.InvalidArgument) 64 So(w.Body.String(), ShouldEqual, "") 65 }) 66 67 Convey("OK", func() { 68 // Upload a directory node. 69 d := &repb.Directory{ 70 Directories: []*repb.DirectoryNode{ 71 { 72 Name: "subDir", 73 Digest: digest.NewFromBlob([]byte{}).ToProto(), 74 }, 75 }, 76 Files: []*repb.FileNode{ 77 { 78 Name: "foo", 79 Digest: digest.NewFromBlob([]byte{1}).ToProto(), 80 }, 81 }, 82 } 83 b, err := proto.Marshal(d) 84 So(err, ShouldBeNil) 85 bd, err := cl.WriteBlob(context.Background(), b) 86 So(err, ShouldBeNil) 87 88 err = renderTree(ctx, w, cl, &bd, testInstance) 89 90 So(err, ShouldBeNil) 91 body, err := io.ReadAll(w.Body) 92 So(err, ShouldBeNil) 93 // body should contain file name, hash, size. 94 So(string(body), ShouldContainSubstring, d.Files[0].Name) 95 So(string(body), ShouldContainSubstring, d.Files[0].Digest.Hash) 96 So(string(body), ShouldContainSubstring, "1 B") 97 }) 98 }) 99 100 Convey("returnBlob", t, func() { 101 cl := fakeClient(ctx, t) 102 103 Convey("Not Found", func() { 104 // This blob doesn't exist on CAS. 105 bd := digest.NewFromBlob([]byte{1}) 106 107 err := returnBlob(ctx, w, cl, &bd, "") 108 109 So(grpcutil.Code(err), ShouldEqual, codes.NotFound) 110 So(w.Body.String(), ShouldEqual, "") 111 }) 112 113 Convey("OK", func() { 114 // Upload a blob. 115 b := []byte{1} 116 bd, err := cl.WriteBlob(context.Background(), b) 117 So(err, ShouldBeNil) 118 119 err = returnBlob(ctx, w, cl, &bd, "test.txt") 120 121 So(err, ShouldBeNil) 122 body, err := io.ReadAll(w.Body) 123 So(err, ShouldBeNil) 124 So(body, ShouldResemble, b) 125 }) 126 }) 127 } 128 129 // fakeClient returns a Client for a fake CAS. 130 func fakeClient(ctx context.Context, t *testing.T) *client.Client { 131 casSrv, err := fakes.NewServer(t) 132 So(err, ShouldBeNil) 133 t.Cleanup(casSrv.Clear) 134 cl, err := casSrv.NewTestClient(ctx) 135 So(err, ShouldBeNil) 136 t.Cleanup(func() { 137 cl.Close() // ignore error. 138 }) 139 return cl 140 }