github.com/xmidt-org/webpa-common@v1.11.9/basculechecks/metricvalidator_test.go (about) 1 /** 2 * Copyright 2020 Comcast Cable Communications Management, LLC 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 18 package basculechecks 19 20 import ( 21 "context" 22 "errors" 23 "net/url" 24 "regexp" 25 "testing" 26 27 "github.com/go-kit/kit/metrics/generic" 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/mock" 30 "github.com/stretchr/testify/require" 31 "github.com/xmidt-org/bascule" 32 ) 33 34 func TestMetricValidatorFunc(t *testing.T) { 35 goodURL, err := url.Parse("/test") 36 require.Nil(t, err) 37 capabilities := []string{ 38 "test", 39 "a", 40 "joweiafuoiuoiwauf", 41 "it's a match", 42 } 43 goodAttributes := bascule.NewAttributes(map[string]interface{}{ 44 CapabilityKey: capabilities, 45 "allowedResources": map[string]interface{}{ 46 "allowedPartners": []string{"meh"}, 47 }, 48 }) 49 50 tests := []struct { 51 description string 52 includeAuth bool 53 attributes bascule.Attributes 54 checkCallExpected bool 55 checkReason string 56 checkErr error 57 errorOut bool 58 errExpected bool 59 }{ 60 { 61 description: "Success", 62 includeAuth: true, 63 attributes: goodAttributes, 64 checkCallExpected: true, 65 errorOut: true, 66 }, 67 { 68 description: "Include Auth Error", 69 errorOut: true, 70 errExpected: true, 71 }, 72 { 73 description: "Include Auth Suppressed Error", 74 errorOut: false, 75 }, 76 { 77 description: "Prep Metrics Error", 78 includeAuth: true, 79 attributes: nil, 80 errorOut: true, 81 errExpected: true, 82 }, 83 { 84 description: "Prep Metrics Suppressed Error", 85 includeAuth: true, 86 attributes: nil, 87 errorOut: false, 88 }, 89 { 90 description: "Check Error", 91 includeAuth: true, 92 attributes: goodAttributes, 93 checkCallExpected: true, 94 checkReason: NoCapabilitiesMatch, 95 checkErr: errors.New("test check error"), 96 errorOut: true, 97 errExpected: true, 98 }, 99 { 100 description: "Check Suppressed Error", 101 includeAuth: true, 102 attributes: goodAttributes, 103 checkCallExpected: true, 104 checkReason: NoCapabilitiesMatch, 105 checkErr: errors.New("test check error"), 106 errorOut: false, 107 }, 108 } 109 for _, tc := range tests { 110 t.Run(tc.description, func(t *testing.T) { 111 assert := assert.New(t) 112 113 ctx := context.Background() 114 auth := bascule.Authentication{ 115 Token: bascule.NewToken("test", "princ", tc.attributes), 116 Request: bascule.Request{ 117 URL: goodURL, 118 Method: "GET", 119 }, 120 } 121 if tc.includeAuth { 122 ctx = bascule.WithAuthentication(ctx, auth) 123 } 124 mockCapabilitiesChecker := new(mockCapabilitiesChecker) 125 if tc.checkCallExpected { 126 mockCapabilitiesChecker.On("Check", mock.Anything, mock.Anything).Return(tc.checkReason, tc.checkErr).Once() 127 } 128 129 counter := generic.NewCounter("test_capability_check") 130 mockMeasures := AuthCapabilityCheckMeasures{ 131 CapabilityCheckOutcome: counter, 132 } 133 134 m := MetricValidator{ 135 C: mockCapabilitiesChecker, 136 Measures: &mockMeasures, 137 } 138 err := m.CreateValidator(tc.errorOut)(ctx, nil) 139 mockCapabilitiesChecker.AssertExpectations(t) 140 if tc.errExpected { 141 assert.NotNil(err) 142 return 143 } 144 assert.Nil(err) 145 }) 146 } 147 } 148 149 func TestPrepMetrics(t *testing.T) { 150 var ( 151 goodURL = "/asnkfn/aefkijeoij/aiogj" 152 matchingURL = "/fnvvdsjkfji/mac:12345544322345334/geigosj" 153 client = "special" 154 prepErr = errors.New("couldn't get partner IDs from attributes") 155 badValErr = errors.New("couldn't be cast to string slice") 156 goodEndpoint = `/fnvvdsjkfji/.*/geigosj\b` 157 goodRegex = regexp.MustCompile(goodEndpoint) 158 unusedEndpoint = `/a/b\b` 159 unusedRegex = regexp.MustCompile(unusedEndpoint) 160 ) 161 162 tests := []struct { 163 description string 164 noPartnerID bool 165 partnerIDs interface{} 166 url string 167 includeToken bool 168 includeAttributes bool 169 includeURL bool 170 expectedPartner string 171 expectedEndpoint string 172 expectedReason string 173 expectedErr error 174 }{ 175 { 176 description: "Success", 177 partnerIDs: []string{"partner"}, 178 url: goodURL, 179 includeToken: true, 180 includeAttributes: true, 181 includeURL: true, 182 expectedPartner: "partner", 183 expectedEndpoint: "not_recognized", 184 expectedReason: "", 185 expectedErr: nil, 186 }, 187 { 188 description: "Success Abridged URL", 189 partnerIDs: []string{"partner"}, 190 url: matchingURL, 191 includeToken: true, 192 includeAttributes: true, 193 includeURL: true, 194 expectedPartner: "partner", 195 expectedEndpoint: goodEndpoint, 196 expectedReason: "", 197 expectedErr: nil, 198 }, 199 { 200 description: "Nil Token Error", 201 expectedReason: TokenMissingValues, 202 expectedErr: ErrNoToken, 203 }, 204 { 205 description: "Nil Token Attributes Error", 206 url: goodURL, 207 includeToken: true, 208 expectedReason: TokenMissingValues, 209 expectedErr: ErrNilAttributes, 210 }, 211 { 212 description: "No Partner ID Error", 213 noPartnerID: true, 214 url: goodURL, 215 includeToken: true, 216 includeAttributes: true, 217 expectedPartner: "", 218 expectedEndpoint: "", 219 expectedReason: UndeterminedPartnerID, 220 expectedErr: prepErr, 221 }, 222 { 223 description: "Non String Slice Partner ID Error", 224 partnerIDs: []int{0, 1, 2}, 225 url: goodURL, 226 includeToken: true, 227 includeAttributes: true, 228 expectedPartner: "", 229 expectedEndpoint: "", 230 expectedReason: UndeterminedPartnerID, 231 expectedErr: badValErr, 232 }, 233 { 234 description: "Non Slice Partner ID Error", 235 partnerIDs: struct{ string }{}, 236 url: goodURL, 237 includeToken: true, 238 includeAttributes: true, 239 expectedPartner: "", 240 expectedEndpoint: "", 241 expectedReason: UndeterminedPartnerID, 242 expectedErr: badValErr, 243 }, 244 { 245 description: "Nil URL Error", 246 partnerIDs: []string{"partner"}, 247 url: goodURL, 248 includeToken: true, 249 includeAttributes: true, 250 expectedPartner: "partner", 251 expectedReason: TokenMissingValues, 252 expectedErr: ErrNoURL, 253 }, 254 } 255 256 m := MetricValidator{ 257 Endpoints: []*regexp.Regexp{unusedRegex, goodRegex}, 258 } 259 260 for _, tc := range tests { 261 t.Run(tc.description, func(t *testing.T) { 262 require := require.New(t) 263 assert := assert.New(t) 264 265 // setup auth 266 token := bascule.NewToken("mehType", client, nil) 267 if tc.includeAttributes { 268 a := map[string]interface{}{ 269 "allowedResources": map[string]interface{}{ 270 "allowedPartners": tc.partnerIDs, 271 }, 272 } 273 274 if tc.noPartnerID { 275 a["allowedResources"] = 5 276 } 277 attributes := bascule.NewAttributes(a) 278 token = bascule.NewToken("mehType", client, attributes) 279 } 280 auth := bascule.Authentication{ 281 Authorization: "testAuth", 282 Request: bascule.Request{ 283 Method: "get", 284 }, 285 } 286 if tc.includeToken { 287 auth.Token = token 288 } 289 if tc.includeURL { 290 u, err := url.ParseRequestURI(tc.url) 291 require.Nil(err) 292 auth.Request.URL = u 293 } 294 295 c, partner, endpoint, reason, err := m.prepMetrics(auth) 296 if tc.includeToken { 297 assert.Equal(client, c) 298 } 299 assert.Equal(tc.expectedPartner, partner) 300 assert.Equal(tc.expectedEndpoint, endpoint) 301 assert.Equal(tc.expectedReason, reason) 302 if err == nil || tc.expectedErr == nil { 303 assert.Equal(tc.expectedErr, err) 304 } else { 305 assert.Contains(err.Error(), tc.expectedErr.Error()) 306 } 307 }) 308 } 309 } 310 311 func TestDeterminePartnerMetric(t *testing.T) { 312 tests := []struct { 313 description string 314 partnersInput []string 315 expectedResult string 316 }{ 317 { 318 description: "No Partners", 319 expectedResult: "none", 320 }, 321 { 322 description: "one wildcard", 323 partnersInput: []string{"*"}, 324 expectedResult: "wildcard", 325 }, 326 { 327 description: "one partner", 328 partnersInput: []string{"TestPartner"}, 329 expectedResult: "TestPartner", 330 }, 331 { 332 description: "many partners", 333 partnersInput: []string{"partner1", "partner2", "partner3"}, 334 expectedResult: "many", 335 }, 336 { 337 description: "many partners with wildcard", 338 partnersInput: []string{"partner1", "partner2", "partner3", "*"}, 339 expectedResult: "wildcard", 340 }, 341 } 342 343 for _, tc := range tests { 344 t.Run(tc.description, func(t *testing.T) { 345 assert := assert.New(t) 346 partner := DeterminePartnerMetric(tc.partnersInput) 347 assert.Equal(tc.expectedResult, partner) 348 }) 349 } 350 }