go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/gerrit/instrumented_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 gerrit 16 17 import ( 18 "context" 19 "fmt" 20 "net/http" 21 "net/http/httptest" 22 "net/url" 23 "testing" 24 "time" 25 26 "google.golang.org/grpc/codes" 27 "google.golang.org/grpc/status" 28 29 "go.chromium.org/luci/common/clock/testclock" 30 "go.chromium.org/luci/common/logging" 31 "go.chromium.org/luci/common/logging/gologger" 32 gerritpb "go.chromium.org/luci/common/proto/gerrit" 33 "go.chromium.org/luci/common/tsmon" 34 "go.chromium.org/luci/common/tsmon/distribution" 35 "go.chromium.org/luci/common/tsmon/store" 36 "go.chromium.org/luci/common/tsmon/target" 37 "go.chromium.org/luci/common/tsmon/types" 38 "go.chromium.org/luci/gae/impl/memory" 39 "go.chromium.org/luci/gae/service/datastore" 40 "go.chromium.org/luci/server/auth" 41 "go.chromium.org/luci/server/auth/authtest" 42 43 . "github.com/smartystreets/goconvey/convey" 44 ) 45 46 func TestInstrumentedFactory(t *testing.T) { 47 t.Parallel() 48 49 Convey("InstrumentedFactory works", t, func() { 50 ctx := context.Background() 51 if testing.Verbose() { 52 ctx = logging.SetLevel(gologger.StdConfig.Use(ctx), logging.Debug) 53 } 54 ctx = memory.Use(ctx) 55 ctx, _, _ = tsmon.WithFakes(ctx) 56 tsmon.GetState(ctx).SetStore(store.NewInMemory(&target.Task{})) 57 ctx = authtest.MockAuthConfig(ctx) 58 epoch := datastore.RoundTime(testclock.TestRecentTimeUTC) 59 ctx, tclock := testclock.UseTime(ctx, epoch) 60 61 mockResp := "" // modified in tests later. 62 mockHTTPCode := http.StatusOK 63 mockDelay := time.Millisecond 64 srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 65 tclock.Add(mockDelay) 66 w.WriteHeader(mockHTTPCode) 67 if mockHTTPCode == http.StatusOK { 68 w.Write([]byte(mockResp)) 69 } 70 })) 71 defer srv.Close() 72 u, err := url.Parse(srv.URL) 73 So(err, ShouldBeNil) 74 gHost := u.Host 75 76 prod, err := newProd(ctx) 77 So(err, ShouldBeNil) 78 prod.baseTransport = srv.Client().Transport 79 prod.mockMintProjectToken = func(context.Context, auth.ProjectTokenParams) (*auth.Token, error) { 80 return &auth.Token{ 81 Token: "token", 82 Expiry: tclock.Now().Add(2 * time.Minute), 83 }, nil 84 } 85 86 f := InstrumentedFactory(prod) 87 c1, err := f.MakeClient(ctx, gHost, "prj1") 88 So(err, ShouldBeNil) 89 c2, err := f.MakeClient(ctx, gHost, "prj2") 90 So(err, ShouldBeNil) 91 92 mockDelay, mockHTTPCode, mockResp = time.Second, http.StatusOK, ")]}'\n[]" // no changes. 93 r1, err := c1.ListChanges(ctx, &gerritpb.ListChangesRequest{}) 94 So(err, ShouldBeNil) 95 So(r1.GetChanges(), ShouldBeEmpty) 96 So(tsmonSentCounter(ctx, metricCount, "prj1", gHost, "ListChanges", "OK"), ShouldEqual, 1) 97 d1 := tsmonSentDistr(ctx, metricDurationMS, "prj1", gHost, "ListChanges", "OK") 98 So(d1.Sum(), ShouldEqual, mockDelay.Milliseconds()) 99 100 mockDelay, mockHTTPCode, mockResp = time.Millisecond, http.StatusNotFound, "" 101 _, err = c2.GetChange(ctx, &gerritpb.GetChangeRequest{Number: 1}) 102 So(status.Code(err), ShouldEqual, codes.NotFound) 103 So(tsmonSentCounter(ctx, metricCount, "prj2", gHost, "GetChange", "NOT_FOUND"), ShouldEqual, 1) 104 d2 := tsmonSentDistr(ctx, metricDurationMS, "prj2", gHost, "GetChange", "NOT_FOUND") 105 So(d2.Sum(), ShouldEqual, mockDelay.Milliseconds()) 106 }) 107 } 108 109 func tsmonSentDistr(ctx context.Context, m types.Metric, fieldVals ...any) *distribution.Distribution { 110 resetTime := time.Time{} 111 d, ok := tsmon.GetState(ctx).Store().Get(ctx, m, resetTime, fieldVals).(*distribution.Distribution) 112 if !ok { 113 panic(fmt.Errorf("either metric isn't a Distribution or nothing sent with metric fields %s", fieldVals)) 114 } 115 return d 116 } 117 118 func tsmonSentCounter(ctx context.Context, m types.Metric, fieldVals ...any) int64 { 119 resetTime := time.Time{} 120 v, ok := tsmon.GetState(ctx).Store().Get(ctx, m, resetTime, fieldVals).(int64) 121 if !ok { 122 panic(fmt.Errorf("either metric isn't a Counter or nothing sent with metric fields %s", fieldVals)) 123 } 124 return v 125 }