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  }