github.com/grafana/pyroscope@v1.18.0/pkg/featureflags/client_capability_test.go (about) 1 package featureflags 2 3 import ( 4 "net/http" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 ) 9 10 func Test_parseClientCapabilities(t *testing.T) { 11 tests := []struct { 12 Name string 13 Header http.Header 14 Want ClientCapabilities 15 WantError bool 16 ErrorMessage string 17 }{ 18 { 19 Name: "empty header returns default capabilities", 20 Header: http.Header{}, 21 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 22 }, 23 { 24 Name: "no Accept header returns default capabilities", 25 Header: http.Header{ 26 "Content-Type": []string{"application/json"}, 27 }, 28 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 29 }, 30 { 31 Name: "empty Accept header value returns default capabilities", 32 Header: http.Header{ 33 "Accept": []string{""}, 34 }, 35 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 36 }, 37 { 38 Name: "simple Accept header without capabilities", 39 Header: http.Header{ 40 "Accept": []string{"application/json"}, 41 }, 42 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 43 }, 44 { 45 Name: "Accept header with utf8 label names capability true", 46 Header: http.Header{ 47 "Accept": []string{"*/*; allow-utf8-labelnames=true"}, 48 }, 49 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 50 }, 51 { 52 Name: "Accept header with utf8 label names capability false", 53 Header: http.Header{ 54 "Accept": []string{"*/*; allow-utf8-labelnames=false"}, 55 }, 56 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 57 }, 58 { 59 Name: "Accept header with utf8 label names capability invalid value", 60 Header: http.Header{ 61 "Accept": []string{"*/*; allow-utf8-labelnames=invalid"}, 62 }, 63 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 64 }, 65 { 66 Name: "Accept header with unknown capability", 67 Header: http.Header{ 68 "Accept": []string{"*/*; unknown-capability=true"}, 69 }, 70 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 71 }, 72 { 73 Name: "Accept header with multiple capabilities", 74 Header: http.Header{ 75 "Accept": []string{"*/*; allow-utf8-labelnames=true; unknown-capability=false"}, 76 }, 77 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 78 }, 79 { 80 Name: "multiple Accept header values", 81 Header: http.Header{ 82 "Accept": []string{"application/json", "*/*; allow-utf8-labelnames=true"}, 83 }, 84 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 85 }, 86 { 87 Name: "multiple Accept header values with different capabilities", 88 Header: http.Header{ 89 "Accept": []string{ 90 "application/json; allow-utf8-labelnames=false", 91 "*/*; allow-utf8-labelnames=true", 92 }, 93 }, 94 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 95 }, 96 { 97 Name: "Accept header with quality values", 98 Header: http.Header{ 99 "Accept": []string{"text/html; q=0.9; allow-utf8-labelnames=true"}, 100 }, 101 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 102 }, 103 { 104 Name: "complex Accept header", 105 Header: http.Header{ 106 "Accept": []string{ 107 "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;allow-utf8-labelnames=true", 108 }, 109 }, 110 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 111 }, 112 { 113 Name: "multiple Accept header entries", 114 Header: http.Header{ 115 "Accept": []string{ 116 "application/json", 117 "text/plain; allow-utf8-labelnames=true", 118 "*/*; q=0.1", 119 }, 120 }, 121 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 122 }, 123 { 124 Name: "invalid mime type in Accept header", 125 Header: http.Header{ 126 "Accept": []string{"invalid/mime/type/format"}, 127 }, 128 Want: ClientCapabilities{}, 129 WantError: true, 130 ErrorMessage: "mime: unexpected content after media subtype", 131 }, 132 { 133 Name: "Accept header with invalid syntax", 134 Header: http.Header{ 135 "Accept": []string{"text/html; invalid-parameter-syntax"}, 136 }, 137 Want: ClientCapabilities{}, 138 WantError: true, 139 ErrorMessage: "mime: invalid media parameter", 140 }, 141 { 142 Name: "mixed valid and invalid Accept header values", 143 Header: http.Header{ 144 "Accept": []string{ 145 "application/json", 146 "invalid/mime/type/format", 147 }, 148 }, 149 Want: ClientCapabilities{}, 150 WantError: true, 151 ErrorMessage: "mime: unexpected content after media subtype", 152 }, 153 { 154 // Parameter names are case-insensitive in mime.ParseMediaType 155 Name: "case sensitivity test for capability name", 156 Header: http.Header{ 157 "Accept": []string{"*/*; Allow-Utf8-Labelnames=true"}, 158 }, 159 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 160 }, 161 { 162 Name: "whitespace handling in Accept header", 163 Header: http.Header{ 164 "Accept": []string{" application/json ; allow-utf8-labelnames=true "}, 165 }, 166 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 167 }, 168 } 169 170 for _, tt := range tests { 171 t.Run(tt.Name, func(t *testing.T) { 172 t.Parallel() 173 174 got, err := parseClientCapabilities(tt.Header) 175 176 if tt.WantError { 177 require.Error(t, err) 178 if tt.ErrorMessage != "" { 179 require.Contains(t, err.Error(), tt.ErrorMessage) 180 } 181 return 182 } 183 184 require.NoError(t, err) 185 require.Equal(t, tt.Want, got) 186 }) 187 } 188 } 189 190 func Test_parseClientCapabilities_MultipleCapabilities(t *testing.T) { 191 // This test specifically checks that when the same capability appears 192 // multiple times with different values, the last "true" value wins 193 tests := []struct { 194 Name string 195 Header http.Header 196 Want ClientCapabilities 197 }{ 198 { 199 Name: "capability appears multiple times - last true wins", 200 Header: http.Header{ 201 "Accept": []string{ 202 "application/json; allow-utf8-labelnames=false", 203 "text/plain; allow-utf8-labelnames=true", 204 }, 205 }, 206 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 207 }, 208 { 209 Name: "capability appears multiple times - last false loses to earlier true", 210 Header: http.Header{ 211 "Accept": []string{ 212 "application/json; allow-utf8-labelnames=true", 213 "text/plain; allow-utf8-labelnames=false", 214 }, 215 }, 216 Want: ClientCapabilities{AllowUtf8LabelNames: true}, 217 }, 218 { 219 Name: "capability appears multiple times - all false", 220 Header: http.Header{ 221 "Accept": []string{ 222 "application/json; allow-utf8-labelnames=false", 223 "text/plain; allow-utf8-labelnames=false", 224 }, 225 }, 226 Want: ClientCapabilities{AllowUtf8LabelNames: false}, 227 }, 228 } 229 230 for _, tt := range tests { 231 t.Run(tt.Name, func(t *testing.T) { 232 t.Parallel() 233 234 got, err := parseClientCapabilities(tt.Header) 235 require.NoError(t, err) 236 require.Equal(t, tt.Want, got) 237 }) 238 } 239 }