google.golang.org/grpc@v1.74.2/balancer/ringhash/config_test.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package ringhash
    20  
    21  import (
    22  	"encoding/json"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  
    27  	"google.golang.org/grpc/internal/envconfig"
    28  	iringhash "google.golang.org/grpc/internal/ringhash"
    29  	"google.golang.org/grpc/internal/testutils"
    30  )
    31  
    32  func (s) TestParseConfig(t *testing.T) {
    33  	tests := []struct {
    34  		name                string
    35  		js                  string
    36  		envConfigCap        uint64
    37  		requestHeaderEnvVar bool
    38  		want                *iringhash.LBConfig
    39  		wantErr             bool
    40  	}{
    41  		{
    42  			name:                "OK",
    43  			js:                  `{"minRingSize": 1, "maxRingSize": 2}`,
    44  			requestHeaderEnvVar: true,
    45  			want:                &iringhash.LBConfig{MinRingSize: 1, MaxRingSize: 2},
    46  		},
    47  		{
    48  			name:                "OK with default min",
    49  			js:                  `{"maxRingSize": 2000}`,
    50  			requestHeaderEnvVar: true,
    51  			want:                &iringhash.LBConfig{MinRingSize: defaultMinSize, MaxRingSize: 2000},
    52  		},
    53  		{
    54  			name:                "OK with default max",
    55  			js:                  `{"minRingSize": 2000}`,
    56  			requestHeaderEnvVar: true,
    57  			want:                &iringhash.LBConfig{MinRingSize: 2000, MaxRingSize: defaultMaxSize},
    58  		},
    59  		{
    60  			name:                "min greater than max",
    61  			js:                  `{"minRingSize": 10, "maxRingSize": 2}`,
    62  			requestHeaderEnvVar: true,
    63  			want:                nil,
    64  			wantErr:             true,
    65  		},
    66  		{
    67  			name:                "min greater than max greater than global limit",
    68  			js:                  `{"minRingSize": 6000, "maxRingSize": 5000}`,
    69  			requestHeaderEnvVar: true,
    70  			want:                nil,
    71  			wantErr:             true,
    72  		},
    73  		{
    74  			name:                "max greater than global limit",
    75  			js:                  `{"minRingSize": 1, "maxRingSize": 6000}`,
    76  			requestHeaderEnvVar: true,
    77  			want:                &iringhash.LBConfig{MinRingSize: 1, MaxRingSize: 4096},
    78  		},
    79  		{
    80  			name:                "min and max greater than global limit",
    81  			js:                  `{"minRingSize": 5000, "maxRingSize": 6000}`,
    82  			requestHeaderEnvVar: true,
    83  			want:                &iringhash.LBConfig{MinRingSize: 4096, MaxRingSize: 4096},
    84  		},
    85  		{
    86  			name:                "min and max less than raised global limit",
    87  			js:                  `{"minRingSize": 5000, "maxRingSize": 6000}`,
    88  			envConfigCap:        8000,
    89  			requestHeaderEnvVar: true,
    90  			want:                &iringhash.LBConfig{MinRingSize: 5000, MaxRingSize: 6000},
    91  		},
    92  		{
    93  			name:                "min and max greater than raised global limit",
    94  			js:                  `{"minRingSize": 10000, "maxRingSize": 10000}`,
    95  			envConfigCap:        8000,
    96  			requestHeaderEnvVar: true,
    97  			want:                &iringhash.LBConfig{MinRingSize: 8000, MaxRingSize: 8000},
    98  		},
    99  		{
   100  			name:                "min greater than upper bound",
   101  			js:                  `{"minRingSize": 8388610, "maxRingSize": 10}`,
   102  			requestHeaderEnvVar: true,
   103  			want:                nil,
   104  			wantErr:             true,
   105  		},
   106  		{
   107  			name:                "max greater than upper bound",
   108  			js:                  `{"minRingSize": 10, "maxRingSize": 8388610}`,
   109  			requestHeaderEnvVar: true,
   110  			want:                nil,
   111  			wantErr:             true,
   112  		},
   113  		{
   114  			name:                "request metadata key set",
   115  			js:                  `{"requestHashHeader": "x-foo"}`,
   116  			requestHeaderEnvVar: true,
   117  			want: &iringhash.LBConfig{
   118  				MinRingSize:       defaultMinSize,
   119  				MaxRingSize:       defaultMaxSize,
   120  				RequestHashHeader: "x-foo",
   121  			},
   122  		},
   123  		{
   124  			name:                "request metadata key set with uppercase letters",
   125  			js:                  `{"requestHashHeader": "x-FOO"}`,
   126  			requestHeaderEnvVar: true,
   127  			want: &iringhash.LBConfig{
   128  				MinRingSize:       defaultMinSize,
   129  				MaxRingSize:       defaultMaxSize,
   130  				RequestHashHeader: "x-foo",
   131  			},
   132  		},
   133  		{
   134  			name:                "invalid request hash header",
   135  			js:                  `{"requestHashHeader": "!invalid"}`,
   136  			requestHeaderEnvVar: true,
   137  			want:                nil,
   138  			wantErr:             true,
   139  		},
   140  		{
   141  			name:                "binary request hash header",
   142  			js:                  `{"requestHashHeader": "header-with-bin"}`,
   143  			requestHeaderEnvVar: true,
   144  			want:                nil,
   145  			wantErr:             true,
   146  		},
   147  		{
   148  			name:                "request hash header cleared when RingHashSetRequestHashKey env var is false",
   149  			js:                  `{"requestHashHeader": "x-foo"}`,
   150  			requestHeaderEnvVar: false,
   151  			want: &iringhash.LBConfig{
   152  				MinRingSize: defaultMinSize,
   153  				MaxRingSize: defaultMaxSize,
   154  			},
   155  		},
   156  	}
   157  	for _, tt := range tests {
   158  		t.Run(tt.name, func(t *testing.T) {
   159  			if tt.envConfigCap != 0 {
   160  				testutils.SetEnvConfig(t, &envconfig.RingHashCap, tt.envConfigCap)
   161  			}
   162  			testutils.SetEnvConfig(t, &envconfig.RingHashSetRequestHashKey, tt.requestHeaderEnvVar)
   163  			got, err := parseConfig(json.RawMessage(tt.js))
   164  			if (err != nil) != tt.wantErr {
   165  				t.Errorf("parseConfig() error = %v, wantErr %v", err, tt.wantErr)
   166  				return
   167  			}
   168  			if diff := cmp.Diff(got, tt.want); diff != "" {
   169  				t.Errorf("parseConfig() got unexpected output, diff (-got +want): %v", diff)
   170  			}
   171  		})
   172  	}
   173  }