github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/integration/metrics_test.go (about) 1 // Copyright 2017 The etcd 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 integration 16 17 import ( 18 "context" 19 "fmt" 20 "net/http" 21 "strconv" 22 "testing" 23 "time" 24 25 pb "github.com/lfch/etcd-io/api/v3/etcdserverpb" 26 "github.com/lfch/etcd-io/client/pkg/v3/transport" 27 "github.com/lfch/etcd-io/server/v3/storage" 28 "github.com/lfch/etcd-io/tests/v3/framework/integration" 29 ) 30 31 // TestMetricDbSizeBoot checks that the db size metric is set on boot. 32 func TestMetricDbSizeBoot(t *testing.T) { 33 integration.BeforeTest(t) 34 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 35 defer clus.Terminate(t) 36 37 v, err := clus.Members[0].Metric("etcd_debugging_mvcc_db_total_size_in_bytes") 38 if err != nil { 39 t.Fatal(err) 40 } 41 42 if v == "0" { 43 t.Fatalf("expected non-zero, got %q", v) 44 } 45 } 46 47 func TestMetricDbSizeDefrag(t *testing.T) { 48 testMetricDbSizeDefrag(t, "etcd") 49 } 50 51 // testMetricDbSizeDefrag checks that the db size metric is set after defrag. 52 func testMetricDbSizeDefrag(t *testing.T, name string) { 53 integration.BeforeTest(t) 54 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 55 defer clus.Terminate(t) 56 57 kvc := integration.ToGRPC(clus.Client(0)).KV 58 mc := integration.ToGRPC(clus.Client(0)).Maintenance 59 60 // expand the db size 61 numPuts := 25 // large enough to write more than 1 page 62 putreq := &pb.PutRequest{Key: []byte("k"), Value: make([]byte, 4096)} 63 for i := 0; i < numPuts; i++ { 64 time.Sleep(10 * time.Millisecond) // to execute multiple backend txn 65 if _, err := kvc.Put(context.TODO(), putreq); err != nil { 66 t.Fatal(err) 67 } 68 } 69 70 // wait for backend txn sync 71 time.Sleep(500 * time.Millisecond) 72 73 expected := numPuts * len(putreq.Value) 74 beforeDefrag, err := clus.Members[0].Metric(name + "_mvcc_db_total_size_in_bytes") 75 if err != nil { 76 t.Fatal(err) 77 } 78 bv, err := strconv.Atoi(beforeDefrag) 79 if err != nil { 80 t.Fatal(err) 81 } 82 if bv < expected { 83 t.Fatalf("expected db size greater than %d, got %d", expected, bv) 84 } 85 beforeDefragInUse, err := clus.Members[0].Metric("etcd_mvcc_db_total_size_in_use_in_bytes") 86 if err != nil { 87 t.Fatal(err) 88 } 89 biu, err := strconv.Atoi(beforeDefragInUse) 90 if err != nil { 91 t.Fatal(err) 92 } 93 if biu < expected { 94 t.Fatalf("expected db size in use is greater than %d, got %d", expected, biu) 95 } 96 97 // clear out historical keys, in use bytes should free pages 98 creq := &pb.CompactionRequest{Revision: int64(numPuts), Physical: true} 99 if _, kerr := kvc.Compact(context.TODO(), creq); kerr != nil { 100 t.Fatal(kerr) 101 } 102 103 validateAfterCompactionInUse := func() error { 104 // Put to move PendingPages to FreePages 105 if _, err = kvc.Put(context.TODO(), putreq); err != nil { 106 t.Fatal(err) 107 } 108 time.Sleep(500 * time.Millisecond) 109 110 afterCompactionInUse, err := clus.Members[0].Metric("etcd_mvcc_db_total_size_in_use_in_bytes") 111 if err != nil { 112 t.Fatal(err) 113 } 114 aciu, err := strconv.Atoi(afterCompactionInUse) 115 if err != nil { 116 t.Fatal(err) 117 } 118 if biu <= aciu { 119 return fmt.Errorf("expected less than %d, got %d after compaction", biu, aciu) 120 } 121 return nil 122 } 123 124 // backend rollbacks read transaction asynchronously (PR #10523), 125 // which causes the result to be flaky. Retry 3 times. 126 maxRetry, retry := 3, 0 127 for { 128 err := validateAfterCompactionInUse() 129 if err == nil { 130 break 131 } 132 retry++ 133 if retry >= maxRetry { 134 t.Fatalf(err.Error()) 135 } 136 } 137 138 // defrag should give freed space back to fs 139 mc.Defragment(context.TODO(), &pb.DefragmentRequest{}) 140 141 afterDefrag, err := clus.Members[0].Metric(name + "_mvcc_db_total_size_in_bytes") 142 if err != nil { 143 t.Fatal(err) 144 } 145 av, err := strconv.Atoi(afterDefrag) 146 if err != nil { 147 t.Fatal(err) 148 } 149 if bv <= av { 150 t.Fatalf("expected less than %d, got %d after defrag", bv, av) 151 } 152 153 afterDefragInUse, err := clus.Members[0].Metric("etcd_mvcc_db_total_size_in_use_in_bytes") 154 if err != nil { 155 t.Fatal(err) 156 } 157 adiu, err := strconv.Atoi(afterDefragInUse) 158 if err != nil { 159 t.Fatal(err) 160 } 161 if adiu > av { 162 t.Fatalf("db size in use (%d) is expected less than db size (%d) after defrag", adiu, av) 163 } 164 } 165 166 func TestMetricQuotaBackendBytes(t *testing.T) { 167 integration.BeforeTest(t) 168 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 169 defer clus.Terminate(t) 170 171 qs, err := clus.Members[0].Metric("etcd_server_quota_backend_bytes") 172 if err != nil { 173 t.Fatal(err) 174 } 175 qv, err := strconv.ParseFloat(qs, 64) 176 if err != nil { 177 t.Fatal(err) 178 } 179 if int64(qv) != storage.DefaultQuotaBytes { 180 t.Fatalf("expected %d, got %f", storage.DefaultQuotaBytes, qv) 181 } 182 } 183 184 func TestMetricsHealth(t *testing.T) { 185 integration.BeforeTest(t) 186 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 187 defer clus.Terminate(t) 188 189 tr, err := transport.NewTransport(transport.TLSInfo{}, 5*time.Second) 190 if err != nil { 191 t.Fatal(err) 192 } 193 u := clus.Members[0].ClientURLs[0] 194 u.Path = "/health" 195 resp, err := tr.RoundTrip(&http.Request{ 196 Header: make(http.Header), 197 Method: http.MethodGet, 198 URL: &u, 199 }) 200 resp.Body.Close() 201 if err != nil { 202 t.Fatal(err) 203 } 204 205 hv, err := clus.Members[0].Metric("etcd_server_health_failures") 206 if err != nil { 207 t.Fatal(err) 208 } 209 if hv != "0" { 210 t.Fatalf("expected '0' from etcd_server_health_failures, got %q", hv) 211 } 212 }