github.com/xmidt-org/webpa-common@v1.11.9/device/devicegate/filter_test.go (about)

     1  package devicegate
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/xmidt-org/webpa-common/device"
    10  )
    11  
    12  func TestFilterGateAllowConnection(t *testing.T) {
    13  	assert := assert.New(t)
    14  
    15  	metadata := new(device.Metadata)
    16  	metadata.SetClaims(map[string]interface{}{
    17  		"partner-id": "random-partner",
    18  	})
    19  	metadata.Store("random-key", "abc")
    20  
    21  	tests := []struct {
    22  		description string
    23  		filters     map[string]map[interface{}]bool
    24  		canPass     bool
    25  	}{
    26  		{
    27  			description: "Allow",
    28  			canPass:     true,
    29  			filters: map[string]map[interface{}]bool{
    30  				"partner-id": map[interface{}]bool{
    31  					"comcast": true,
    32  				},
    33  			},
    34  		},
    35  		{
    36  			description: "Deny-Filter Match in Claims",
    37  			canPass:     false,
    38  			filters: map[string]map[interface{}]bool{
    39  				"partner-id": map[interface{}]bool{
    40  					"comcast":        true,
    41  					"random-partner": true,
    42  				},
    43  			},
    44  		},
    45  		{
    46  			description: "Deny-Filter Match in Metadata Store",
    47  			canPass:     false,
    48  			filters: map[string]map[interface{}]bool{
    49  				"random-key": map[interface{}]bool{
    50  					"abc":    true,
    51  					"random": true,
    52  				},
    53  			},
    54  		},
    55  	}
    56  
    57  	for _, tc := range tests {
    58  		t.Run(tc.description, func(t *testing.T) {
    59  			mockDevice := new(device.MockDevice)
    60  
    61  			mockDevice.On("Metadata").Return(metadata)
    62  
    63  			filterStore := make(FilterStore)
    64  
    65  			for key, values := range tc.filters {
    66  				fs := FilterSet{
    67  					Set: values,
    68  				}
    69  
    70  				filterStore[key] = &fs
    71  			}
    72  
    73  			fg := FilterGate{
    74  				FilterStore: filterStore,
    75  			}
    76  
    77  			canPass, matchResult := fg.AllowConnection(mockDevice)
    78  			assert.Equal(tc.canPass, canPass)
    79  
    80  			if !tc.canPass {
    81  				assert.NotEmpty(matchResult.Location)
    82  				assert.NotEmpty(matchResult.Key)
    83  			}
    84  
    85  		})
    86  	}
    87  }
    88  
    89  func TestGetSetFilter(t *testing.T) {
    90  	assert := assert.New(t)
    91  	fg := FilterGate{
    92  		FilterStore: make(FilterStore),
    93  	}
    94  
    95  	tests := []struct {
    96  		description   string
    97  		keyToSet      string
    98  		valuesToSet   []interface{}
    99  		keyToGet      string
   100  		expectedSet   Set
   101  		expectedFound bool
   102  	}{
   103  		{
   104  			description:   "Add",
   105  			keyToSet:      "test",
   106  			valuesToSet:   []interface{}{"test", "test1"},
   107  			keyToGet:      "test",
   108  			expectedSet:   &FilterSet{Set: map[interface{}]bool{"test": true, "test1": true}},
   109  			expectedFound: true,
   110  		},
   111  		{
   112  			description:   "Update",
   113  			keyToSet:      "test",
   114  			valuesToSet:   []interface{}{"random-value"},
   115  			keyToGet:      "test",
   116  			expectedSet:   &FilterSet{Set: map[interface{}]bool{"random-value": true}},
   117  			expectedFound: true,
   118  		},
   119  		{
   120  			description: "Not Found",
   121  			keyToGet:    "key-no-exist",
   122  		},
   123  	}
   124  
   125  	for _, tc := range tests {
   126  		t.Run(tc.description, func(t *testing.T) {
   127  			if len(tc.keyToSet) > 0 {
   128  				fg.SetFilter(tc.keyToSet, tc.valuesToSet)
   129  			}
   130  
   131  			getResult, found := fg.GetFilter(tc.keyToGet)
   132  
   133  			assert.Equal(tc.expectedFound, found)
   134  			assert.Equal(tc.expectedSet, getResult)
   135  		})
   136  	}
   137  }
   138  
   139  func TestDeleteFilter(t *testing.T) {
   140  	assert := assert.New(t)
   141  
   142  	fg := FilterGate{
   143  		FilterStore: make(FilterStore),
   144  	}
   145  
   146  	tests := []struct {
   147  		description  string
   148  		keyToDelete  string
   149  		expectedBool bool
   150  	}{
   151  		{
   152  			description:  "Delete existing key",
   153  			keyToDelete:  "test",
   154  			expectedBool: true,
   155  		},
   156  		{
   157  			description:  "Delete non-existent key",
   158  			keyToDelete:  "random-key",
   159  			expectedBool: false,
   160  		},
   161  	}
   162  
   163  	fg.SetFilter("test", []interface{}{"test1", "test2"})
   164  	fg.SetFilter("key", []interface{}{123, 456})
   165  
   166  	for _, tc := range tests {
   167  		t.Run(tc.description, func(t *testing.T) {
   168  			deleted := fg.DeleteFilter(tc.keyToDelete)
   169  
   170  			assert.Equal(tc.expectedBool, deleted)
   171  			assert.Nil(fg.GetFilter(tc.keyToDelete))
   172  		})
   173  	}
   174  }
   175  
   176  func TestGetAllowedFilters(t *testing.T) {
   177  	assert := assert.New(t)
   178  
   179  	tests := []struct {
   180  		description    string
   181  		allowedFilters *FilterSet
   182  		setExists      bool
   183  	}{
   184  		{
   185  			description: "Non-empty allowed filters set",
   186  			allowedFilters: &FilterSet{Set: map[interface{}]bool{
   187  				"test":          true,
   188  				"random-filter": true,
   189  			}},
   190  			setExists: true,
   191  		},
   192  		{
   193  			description:    "Empty allowed filters set",
   194  			allowedFilters: &FilterSet{Set: map[interface{}]bool{}},
   195  			setExists:      true,
   196  		},
   197  		{
   198  			description:    "Nil allowed filters set",
   199  			allowedFilters: nil,
   200  		},
   201  	}
   202  
   203  	for _, tc := range tests {
   204  		t.Run(tc.description, func(t *testing.T) {
   205  			var fg FilterGate
   206  			if tc.allowedFilters != nil {
   207  				fg = FilterGate{
   208  					AllowedFilters: tc.allowedFilters,
   209  				}
   210  			}
   211  
   212  			filters, isSet := fg.GetAllowedFilters()
   213  
   214  			assert.Equal(tc.setExists, isSet)
   215  
   216  			if tc.setExists {
   217  				assert.NotNil(filters)
   218  			} else {
   219  				assert.Nil(filters)
   220  			}
   221  		})
   222  	}
   223  }
   224  
   225  func TestMetadataMatch(t *testing.T) {
   226  	assert := assert.New(t)
   227  	tests := []struct {
   228  		description         string
   229  		claims              map[string]interface{}
   230  		store               map[string]interface{}
   231  		filterKey           string
   232  		filterValues        Set
   233  		expectedMatch       bool
   234  		expectedMatchResult device.MatchResult
   235  	}{
   236  		{
   237  			description: "claims match",
   238  			claims: map[string]interface{}{
   239  				"test":  "test1",
   240  				"test2": "random-value",
   241  			},
   242  			filterKey: "test",
   243  			filterValues: &FilterSet{Set: map[interface{}]bool{
   244  				"test1": true,
   245  				"test2": true,
   246  			}},
   247  			expectedMatch:       true,
   248  			expectedMatchResult: device.MatchResult{Location: claimsLocation, Key: "test"},
   249  		},
   250  		{
   251  			description: "store match",
   252  			store: map[string]interface{}{
   253  				"test":  "test1",
   254  				"test2": "random-value",
   255  			},
   256  			filterKey: "test",
   257  			filterValues: &FilterSet{Set: map[interface{}]bool{
   258  				"test1": true,
   259  				"test2": true,
   260  			}},
   261  			expectedMatch:       true,
   262  			expectedMatchResult: device.MatchResult{Location: metadataMapLocation, Key: "test"},
   263  		},
   264  		{
   265  			description: "array match",
   266  			claims: map[string]interface{}{
   267  				"test":  []interface{}{"test1", "random"},
   268  				"test2": "random-value",
   269  			},
   270  			filterKey: "test",
   271  			filterValues: &FilterSet{Set: map[interface{}]bool{
   272  				"test1": true,
   273  				"test2": true,
   274  			}},
   275  			expectedMatch:       true,
   276  			expectedMatchResult: device.MatchResult{Location: claimsLocation, Key: "test"},
   277  		},
   278  		{
   279  			description: "no value match",
   280  			claims: map[string]interface{}{
   281  				"test":  []interface{}{"test1", "random"},
   282  				"test2": "random-value",
   283  			},
   284  			store: map[string]interface{}{
   285  				"test":  "test1",
   286  				"test2": "random-value",
   287  			},
   288  			filterKey: "test",
   289  			filterValues: &FilterSet{Set: map[interface{}]bool{
   290  				"comcast": true,
   291  				"sky":     true,
   292  			}},
   293  		},
   294  		{
   295  			description: "no key match",
   296  			claims: map[string]interface{}{
   297  				"test":  []interface{}{"test1", "random"},
   298  				"test2": "random-value",
   299  			},
   300  			store: map[string]interface{}{
   301  				"test":  "test1",
   302  				"test2": "random-value",
   303  			},
   304  			filterKey: "random-key",
   305  			filterValues: &FilterSet{Set: map[interface{}]bool{
   306  				"test1":  true,
   307  				"random": true,
   308  			}},
   309  		},
   310  	}
   311  
   312  	for _, tc := range tests {
   313  		t.Run(tc.description, func(t *testing.T) {
   314  			m := new(device.Metadata)
   315  			m.SetClaims(tc.claims)
   316  
   317  			for key, val := range tc.store {
   318  				m.Store(key, val)
   319  			}
   320  
   321  			fs := FilterStore(map[string]Set{
   322  				tc.filterKey: tc.filterValues,
   323  			})
   324  
   325  			match, result := fs.metadataMatch(tc.filterKey, tc.filterValues, m)
   326  			assert.Equal(tc.expectedMatch, match)
   327  			assert.Equal(tc.expectedMatchResult, result)
   328  		})
   329  
   330  	}
   331  }
   332  
   333  func TestMarshalJSON(t *testing.T) {
   334  	assert := assert.New(t)
   335  	tests := []struct {
   336  		description    string
   337  		filterSet      *FilterSet
   338  		expectedOutput []byte
   339  	}{
   340  		{
   341  			description: "Successful String Unmarshal",
   342  			filterSet: &FilterSet{Set: map[interface{}]bool{
   343  				"test1": true,
   344  				"test2": true,
   345  			}},
   346  			expectedOutput: []byte(`["test1","test2"]`),
   347  		},
   348  		{
   349  			description: "Successful Int Unmarshal",
   350  			filterSet: &FilterSet{Set: map[interface{}]bool{
   351  				1: true,
   352  				2: true,
   353  				3: true,
   354  			}},
   355  			expectedOutput: []byte(`[1,2,3]`),
   356  		},
   357  		{
   358  			description:    "Empty Set",
   359  			filterSet:      &FilterSet{Set: map[interface{}]bool{}},
   360  			expectedOutput: []byte(`[]`),
   361  		},
   362  		{
   363  			description:    "Nil Set",
   364  			filterSet:      nil,
   365  			expectedOutput: []byte(`null`),
   366  		},
   367  	}
   368  
   369  	for _, tc := range tests {
   370  		t.Run(tc.description, func(t *testing.T) {
   371  			JSON, err := json.Marshal(tc.filterSet)
   372  			fmt.Println(string(JSON))
   373  			assert.ElementsMatch(tc.expectedOutput, JSON)
   374  			assert.Nil(err)
   375  		})
   376  
   377  	}
   378  }