k8s.io/apiserver@v0.29.3/pkg/storage/value/encrypt/envelope/metrics/metrics_test.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package metrics
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  
    26  	"google.golang.org/grpc/codes"
    27  	"google.golang.org/grpc/status"
    28  
    29  	"k8s.io/apimachinery/pkg/util/rand"
    30  	"k8s.io/component-base/metrics/legacyregistry"
    31  	"k8s.io/component-base/metrics/testutil"
    32  )
    33  
    34  const (
    35  	testKeyHash1              = "sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
    36  	testKeyHash2              = "sha256:d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
    37  	testKeyHash3              = "sha256:4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce"
    38  	testProviderNameForMetric = "providerName"
    39  	testAPIServerID           = "testAPIServerID"
    40  	testAPIServerIDHash       = "sha256:14f9d63e669337ac6bfda2e2162915ee6a6067743eddd4e5c374b572f951ff37"
    41  )
    42  
    43  var (
    44  	errCode = "empty"
    45  )
    46  
    47  func TestRecordKMSOperationLatency(t *testing.T) {
    48  	testCases := []struct {
    49  		name         string
    50  		methodName   string
    51  		duration     time.Duration
    52  		operationErr error
    53  		want         string
    54  	}{
    55  		{
    56  			name:         "operation success",
    57  			methodName:   "/v2alpha1.KeyManagementService/Encrypt",
    58  			duration:     1 * time.Second,
    59  			operationErr: nil,
    60  			want: `
    61  			# HELP apiserver_envelope_encryption_kms_operations_latency_seconds [ALPHA] KMS operation duration with gRPC error code status total.
    62  			# TYPE apiserver_envelope_encryption_kms_operations_latency_seconds histogram
    63  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0001"} 0
    64  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0002"} 0
    65  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0004"} 0
    66  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0008"} 0
    67  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0016"} 0
    68  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0032"} 0
    69  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0064"} 0
    70  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0128"} 0
    71  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0256"} 0
    72  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0512"} 0
    73  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.1024"} 0
    74  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.2048"} 0
    75  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.4096"} 0
    76  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.8192"} 0
    77  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="1.6384"} 1
    78  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="3.2768"} 1
    79  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="6.5536"} 1
    80  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="13.1072"} 1
    81  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="26.2144"} 1
    82  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="52.4288"} 1
    83  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="+Inf"} 1
    84  			apiserver_envelope_encryption_kms_operations_latency_seconds_sum{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
    85  			apiserver_envelope_encryption_kms_operations_latency_seconds_count{grpc_status_code="OK",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
    86  			`,
    87  		},
    88  		{
    89  			name:         "operation error",
    90  			methodName:   "/v2alpha1.KeyManagementService/Encrypt",
    91  			duration:     1 * time.Second,
    92  			operationErr: status.Error(codes.Internal, "some error"),
    93  			want: `
    94  			# HELP apiserver_envelope_encryption_kms_operations_latency_seconds [ALPHA] KMS operation duration with gRPC error code status total.
    95  			# TYPE apiserver_envelope_encryption_kms_operations_latency_seconds histogram
    96  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0001"} 0
    97  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0002"} 0
    98  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0004"} 0
    99  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0008"} 0
   100  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0016"} 0
   101  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0032"} 0
   102  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0064"} 0
   103  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0128"} 0
   104  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0256"} 0
   105  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0512"} 0
   106  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.1024"} 0
   107  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.2048"} 0
   108  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.4096"} 0
   109  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.8192"} 0
   110  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="1.6384"} 1
   111  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="3.2768"} 1
   112  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="6.5536"} 1
   113  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="13.1072"} 1
   114  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="26.2144"} 1
   115  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="52.4288"} 1
   116  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="+Inf"} 1
   117  			apiserver_envelope_encryption_kms_operations_latency_seconds_sum{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   118  			apiserver_envelope_encryption_kms_operations_latency_seconds_count{grpc_status_code="Internal",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   119  			`,
   120  		},
   121  		{
   122  			name:         "wrapped not found error",
   123  			methodName:   "/v2alpha1.KeyManagementService/Encrypt",
   124  			duration:     1 * time.Second,
   125  			operationErr: fmt.Errorf("some low level thing failed: %w", status.Error(codes.NotFound, "some error")),
   126  			want: `
   127  			# HELP apiserver_envelope_encryption_kms_operations_latency_seconds [ALPHA] KMS operation duration with gRPC error code status total.
   128  			# TYPE apiserver_envelope_encryption_kms_operations_latency_seconds histogram
   129  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0001"} 0
   130  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0002"} 0
   131  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0004"} 0
   132  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0008"} 0
   133  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0016"} 0
   134  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0032"} 0
   135  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0064"} 0
   136  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0128"} 0
   137  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0256"} 0
   138  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0512"} 0
   139  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.1024"} 0
   140  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.2048"} 0
   141  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.4096"} 0
   142  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.8192"} 0
   143  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="1.6384"} 1
   144  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="3.2768"} 1
   145  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="6.5536"} 1
   146  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="13.1072"} 1
   147  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="26.2144"} 1
   148  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="52.4288"} 1
   149  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="+Inf"} 1
   150  			apiserver_envelope_encryption_kms_operations_latency_seconds_sum{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   151  			apiserver_envelope_encryption_kms_operations_latency_seconds_count{grpc_status_code="NotFound",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   152  			`,
   153  		},
   154  		{
   155  			name:         "non gRPC error",
   156  			methodName:   "/v2alpha1.KeyManagementService/Encrypt",
   157  			duration:     1 * time.Second,
   158  			operationErr: fmt.Errorf("some bad thing happened"),
   159  			want: `
   160  			# HELP apiserver_envelope_encryption_kms_operations_latency_seconds [ALPHA] KMS operation duration with gRPC error code status total.
   161  			# TYPE apiserver_envelope_encryption_kms_operations_latency_seconds histogram
   162  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0001"} 0
   163  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0002"} 0
   164  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0004"} 0
   165  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0008"} 0
   166  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0016"} 0
   167  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0032"} 0
   168  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0064"} 0
   169  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0128"} 0
   170  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0256"} 0
   171  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.0512"} 0
   172  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.1024"} 0
   173  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.2048"} 0
   174  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.4096"} 0
   175  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="0.8192"} 0
   176  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="1.6384"} 1
   177  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="3.2768"} 1
   178  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="6.5536"} 1
   179  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="13.1072"} 1
   180  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="26.2144"} 1
   181  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="52.4288"} 1
   182  			apiserver_envelope_encryption_kms_operations_latency_seconds_bucket{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName",le="+Inf"} 1
   183  			apiserver_envelope_encryption_kms_operations_latency_seconds_sum{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   184  			apiserver_envelope_encryption_kms_operations_latency_seconds_count{grpc_status_code="unknown-non-grpc",method_name="/v2alpha1.KeyManagementService/Encrypt",provider_name="providerName"} 1
   185  			`,
   186  		},
   187  	}
   188  
   189  	RegisterMetrics()
   190  
   191  	for _, tt := range testCases {
   192  		t.Run(tt.name, func(t *testing.T) {
   193  			RecordKMSOperationLatency("providerName", tt.methodName, tt.duration, tt.operationErr)
   194  			defer KMSOperationsLatencyMetric.Reset()
   195  			if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), "apiserver_envelope_encryption_kms_operations_latency_seconds"); err != nil {
   196  				t.Fatal(err)
   197  			}
   198  		})
   199  	}
   200  }
   201  
   202  func TestRecordKeyID_Serial(t *testing.T) {
   203  	testCases := []struct {
   204  		desc               string
   205  		keyID              string
   206  		metrics            []string
   207  		providerName       string
   208  		transformationType string
   209  		apiServerID        string
   210  		want               string
   211  	}{
   212  		{
   213  			desc:  "keyIDHash total",
   214  			keyID: "1",
   215  			metrics: []string{
   216  				"apiserver_envelope_encryption_key_id_hash_total",
   217  			},
   218  			providerName:       testProviderNameForMetric,
   219  			transformationType: FromStorageLabel,
   220  			apiServerID:        testAPIServerID,
   221  			want: fmt.Sprintf(`
   222  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   223  			# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   224  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   225  			`, testAPIServerIDHash, testKeyHash1, testProviderNameForMetric, FromStorageLabel),
   226  		},
   227  		{
   228  			desc:  "keyIDHash total more labels",
   229  			keyID: "2",
   230  			metrics: []string{
   231  				"apiserver_envelope_encryption_key_id_hash_total",
   232  			},
   233  			providerName:       testProviderNameForMetric,
   234  			transformationType: FromStorageLabel,
   235  			apiServerID:        testAPIServerID,
   236  			want: fmt.Sprintf(`
   237  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   238          	# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   239          	apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   240          	apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   241  			`, testAPIServerIDHash, testKeyHash1, testProviderNameForMetric, FromStorageLabel, testAPIServerIDHash, testKeyHash2, testProviderNameForMetric, FromStorageLabel),
   242  		},
   243  		{
   244  			desc:  "keyIDHash total same labels",
   245  			keyID: "2",
   246  			metrics: []string{
   247  				"apiserver_envelope_encryption_key_id_hash_total",
   248  			},
   249  			providerName:       testProviderNameForMetric,
   250  			transformationType: FromStorageLabel,
   251  			apiServerID:        testAPIServerID,
   252  			want: fmt.Sprintf(`
   253  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   254  			# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   255  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   256  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 2
   257  			`, testAPIServerIDHash, testKeyHash1, testProviderNameForMetric, FromStorageLabel, testAPIServerIDHash, testKeyHash2, testProviderNameForMetric, FromStorageLabel),
   258  		},
   259  		{
   260  			desc:  "keyIDHash total exceeds limit, remove first label, and empty keyID",
   261  			keyID: "",
   262  			metrics: []string{
   263  				"apiserver_envelope_encryption_key_id_hash_total",
   264  			},
   265  			providerName:       testProviderNameForMetric,
   266  			transformationType: FromStorageLabel,
   267  			apiServerID:        testAPIServerID,
   268  			want: fmt.Sprintf(`
   269  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   270  			# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   271  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 2
   272  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   273  			`, testAPIServerIDHash, testKeyHash2, testProviderNameForMetric, FromStorageLabel, testAPIServerIDHash, "", testProviderNameForMetric, FromStorageLabel),
   274  		},
   275  		{
   276  			desc:  "keyIDHash total exceeds limit, remove first label, empty keyID, and empty testAPIServerID",
   277  			keyID: "",
   278  			metrics: []string{
   279  				"apiserver_envelope_encryption_key_id_hash_total",
   280  			},
   281  			providerName:       testProviderNameForMetric,
   282  			transformationType: FromStorageLabel,
   283  			apiServerID:        "",
   284  			want: fmt.Sprintf(`
   285  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   286  			# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   287  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   288  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   289  			`, testAPIServerIDHash, "", testProviderNameForMetric, FromStorageLabel, "", "", testProviderNameForMetric, FromStorageLabel),
   290  		},
   291  		{
   292  			desc:  "keyIDHash total exceeds limit 2, remove first label",
   293  			keyID: "1",
   294  			metrics: []string{
   295  				"apiserver_envelope_encryption_key_id_hash_total",
   296  			},
   297  			providerName:       testProviderNameForMetric,
   298  			transformationType: FromStorageLabel,
   299  			apiServerID:        "",
   300  			want: fmt.Sprintf(`
   301  			# HELP apiserver_envelope_encryption_key_id_hash_total [ALPHA] Number of times a keyID is used split by transformation type, provider, and apiserver identity.
   302  			# TYPE apiserver_envelope_encryption_key_id_hash_total counter
   303  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   304  			apiserver_envelope_encryption_key_id_hash_total{apiserver_id_hash="%s",key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
   305  			`, "", "", testProviderNameForMetric, FromStorageLabel, "", testKeyHash1, testProviderNameForMetric, FromStorageLabel),
   306  		},
   307  	}
   308  
   309  	KeyIDHashTotal.Reset()
   310  	cacheSize = 2
   311  	RegisterMetrics()
   312  	registerLRUMetrics()
   313  
   314  	for _, tt := range testCases {
   315  		t.Run(tt.desc, func(t *testing.T) {
   316  			RecordKeyID(tt.transformationType, tt.providerName, tt.keyID, tt.apiServerID)
   317  			// We are not resetting the metric here as each test is not independent in order to validate the behavior
   318  			// when the metric labels exceed the limit to ensure the labels are not unbounded.
   319  			if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil {
   320  				t.Fatal(err)
   321  			}
   322  		})
   323  	}
   324  }
   325  
   326  func TestRecordKeyIDLRUKey(t *testing.T) {
   327  	RegisterMetrics()
   328  
   329  	cacheSize = 3
   330  	registerLRUMetrics()
   331  	KeyIDHashTotal.Reset()
   332  	defer KeyIDHashTotal.Reset()
   333  
   334  	var wg sync.WaitGroup
   335  	for i := 1; i < 100; i++ {
   336  		wg.Add(1)
   337  		go func() {
   338  			defer wg.Done()
   339  			keyID := rand.String(32)
   340  			apiServerID := rand.String(32)
   341  			key := metricLabels{
   342  				transformationType: rand.String(32),
   343  				providerName:       rand.String(32),
   344  				keyIDHash:          getHash(keyID),
   345  				apiServerIDHash:    getHash(apiServerID),
   346  			}
   347  			RecordKeyID(key.transformationType, key.providerName, keyID, apiServerID)
   348  		}()
   349  	}
   350  	wg.Wait()
   351  
   352  	validMetrics := 0
   353  	metricFamilies, err := legacyregistry.DefaultGatherer.Gather()
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	for _, family := range metricFamilies {
   358  		if family.GetName() != "apiserver_envelope_encryption_key_id_hash_total" {
   359  			continue
   360  		}
   361  		for _, metric := range family.GetMetric() {
   362  			if metric.Counter.GetValue() != 1 {
   363  				t.Errorf("invalid metric seen: %s", metric.String())
   364  			} else {
   365  				validMetrics++
   366  			}
   367  		}
   368  	}
   369  	if validMetrics != cacheSize {
   370  		t.Fatalf("expected total valid metrics to be the same as cacheSize %d, got %d", cacheSize, validMetrics)
   371  	}
   372  }
   373  
   374  func TestRecordKeyIDFromStatus(t *testing.T) {
   375  	RegisterMetrics()
   376  
   377  	cacheSize = 3
   378  	registerLRUMetrics()
   379  	KeyIDHashStatusLastTimestampSeconds.Reset()
   380  	defer KeyIDHashStatusLastTimestampSeconds.Reset()
   381  
   382  	var wg sync.WaitGroup
   383  	for i := 1; i < 100; i++ {
   384  		wg.Add(1)
   385  		go func() {
   386  			defer wg.Done()
   387  			keyID := rand.String(32)
   388  			apiServerID := rand.String(32)
   389  			key := metricLabels{
   390  				providerName:    rand.String(32),
   391  				keyIDHash:       getHash(keyID),
   392  				apiServerIDHash: getHash(apiServerID),
   393  			}
   394  			RecordKeyIDFromStatus(key.providerName, keyID, apiServerID)
   395  		}()
   396  	}
   397  	wg.Wait()
   398  
   399  	validMetrics := 0
   400  	metricFamilies, err := legacyregistry.DefaultGatherer.Gather()
   401  	if err != nil {
   402  		t.Fatal(err)
   403  	}
   404  	for _, family := range metricFamilies {
   405  		if family.GetName() != "apiserver_envelope_encryption_key_id_hash_status_last_timestamp_seconds" {
   406  			continue
   407  		}
   408  		for _, metric := range family.GetMetric() {
   409  			if metric.Gauge.GetValue() == 0 {
   410  				t.Errorf("invalid metric seen: %s", metric.String())
   411  			} else {
   412  				validMetrics++
   413  			}
   414  		}
   415  	}
   416  	if validMetrics != cacheSize {
   417  		t.Fatalf("expected total valid metrics to be the same as cacheSize %d, got %d", cacheSize, validMetrics)
   418  	}
   419  }
   420  
   421  func TestRecordInvalidKeyIDFromStatus(t *testing.T) {
   422  	testCases := []struct {
   423  		desc         string
   424  		count        int
   425  		metrics      []string
   426  		providerName string
   427  		want         string
   428  	}{
   429  		{
   430  			desc:  "invalid KeyID From Status Total 3",
   431  			count: 3,
   432  			metrics: []string{
   433  				"apiserver_envelope_encryption_invalid_key_id_from_status_total",
   434  			},
   435  			providerName: testProviderNameForMetric,
   436  			want: fmt.Sprintf(`
   437  			# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
   438          	# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
   439          	apiserver_envelope_encryption_invalid_key_id_from_status_total{error="%s",provider_name="%s"} %d
   440  			`, errCode, testProviderNameForMetric, 3),
   441  		},
   442  		{
   443  			desc:  "invalid KeyID From Status Total 10",
   444  			count: 10,
   445  			metrics: []string{
   446  				"apiserver_envelope_encryption_invalid_key_id_from_status_total",
   447  			},
   448  			providerName: testProviderNameForMetric,
   449  			want: fmt.Sprintf(`
   450  			# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
   451          	# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
   452          	apiserver_envelope_encryption_invalid_key_id_from_status_total{error="%s",provider_name="%s"} %d
   453  			`, errCode, testProviderNameForMetric, 10),
   454  		},
   455  	}
   456  
   457  	InvalidKeyIDFromStatusTotal.Reset()
   458  	RegisterMetrics()
   459  
   460  	for _, tt := range testCases {
   461  		t.Run(tt.desc, func(t *testing.T) {
   462  			defer InvalidKeyIDFromStatusTotal.Reset()
   463  			var wg sync.WaitGroup
   464  			for i := 0; i < tt.count; i++ {
   465  				wg.Add(1)
   466  				go func() {
   467  					defer wg.Done()
   468  					RecordInvalidKeyIDFromStatus(tt.providerName, errCode)
   469  				}()
   470  			}
   471  			wg.Wait()
   472  
   473  			if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil {
   474  				t.Fatal(err)
   475  			}
   476  		})
   477  	}
   478  }