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 }