github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/ruler/mapper_test.go (about) 1 package ruler 2 3 import ( 4 "net/url" 5 "os" 6 "testing" 7 8 "github.com/go-kit/log" 9 "github.com/go-kit/log/level" 10 "github.com/prometheus/prometheus/pkg/rulefmt" 11 "github.com/spf13/afero" 12 "github.com/stretchr/testify/require" 13 "gopkg.in/yaml.v3" 14 ) 15 16 var ( 17 testUser = "user1" 18 19 fileOneEncoded = url.PathEscape("file /one") 20 fileTwoEncoded = url.PathEscape("file /two") 21 22 fileOnePath = "/rules/user1/" + fileOneEncoded 23 fileTwoPath = "/rules/user1/" + fileTwoEncoded 24 25 specialCharFile = "+A_/ReallyStrange<>NAME:SPACE/?" 26 specialCharFileEncoded = url.PathEscape(specialCharFile) 27 specialCharFilePath = "/rules/user1/" + specialCharFileEncoded 28 29 initialRuleSet map[string][]rulefmt.RuleGroup 30 outOfOrderRuleSet map[string][]rulefmt.RuleGroup 31 updatedRuleSet map[string][]rulefmt.RuleGroup 32 twoFilesRuleSet map[string][]rulefmt.RuleGroup 33 twoFilesUpdatedRuleSet map[string][]rulefmt.RuleGroup 34 twoFilesDeletedRuleSet map[string][]rulefmt.RuleGroup 35 specialCharactersRuleSet map[string][]rulefmt.RuleGroup 36 ) 37 38 func setupRuleSets() { 39 recordNode := yaml.Node{} 40 recordNode.SetString("example_rule") 41 exprNode := yaml.Node{} 42 exprNode.SetString("example_expr") 43 recordNodeUpdated := yaml.Node{} 44 recordNodeUpdated.SetString("example_ruleupdated") 45 exprNodeUpdated := yaml.Node{} 46 exprNodeUpdated.SetString("example_exprupdated") 47 initialRuleSet = map[string][]rulefmt.RuleGroup{ 48 "file /one": { 49 { 50 Name: "rulegroup_one", 51 Rules: []rulefmt.RuleNode{ 52 { 53 Record: recordNode, 54 Expr: exprNode, 55 }, 56 }, 57 }, 58 { 59 Name: "rulegroup_two", 60 Rules: []rulefmt.RuleNode{ 61 { 62 Record: recordNode, 63 Expr: exprNode, 64 }, 65 }, 66 }, 67 }, 68 } 69 outOfOrderRuleSet = map[string][]rulefmt.RuleGroup{ 70 "file /one": { 71 { 72 Name: "rulegroup_two", 73 Rules: []rulefmt.RuleNode{ 74 { 75 Record: recordNode, 76 Expr: exprNode, 77 }, 78 }, 79 }, 80 { 81 Name: "rulegroup_one", 82 Rules: []rulefmt.RuleNode{ 83 { 84 Record: recordNode, 85 Expr: exprNode, 86 }, 87 }, 88 }, 89 }, 90 } 91 updatedRuleSet = map[string][]rulefmt.RuleGroup{ 92 "file /one": { 93 { 94 Name: "rulegroup_one", 95 Rules: []rulefmt.RuleNode{ 96 { 97 Record: recordNode, 98 Expr: exprNode, 99 }, 100 }, 101 }, 102 { 103 Name: "rulegroup_two", 104 Rules: []rulefmt.RuleNode{ 105 { 106 Record: recordNode, 107 Expr: exprNode, 108 }, 109 }, 110 }, 111 { 112 Name: "rulegroup_three", 113 Rules: []rulefmt.RuleNode{ 114 { 115 Record: recordNode, 116 Expr: exprNode, 117 }, 118 }, 119 }, 120 }, 121 } 122 twoFilesRuleSet = map[string][]rulefmt.RuleGroup{ 123 "file /one": { 124 { 125 Name: "rulegroup_one", 126 Rules: []rulefmt.RuleNode{ 127 { 128 Record: recordNode, 129 Expr: exprNode, 130 }, 131 }, 132 }, 133 { 134 Name: "rulegroup_two", 135 Rules: []rulefmt.RuleNode{ 136 { 137 Record: recordNode, 138 Expr: exprNode, 139 }, 140 }, 141 }, 142 }, 143 "file /two": { 144 { 145 Name: "rulegroup_one", 146 Rules: []rulefmt.RuleNode{ 147 { 148 Record: recordNode, 149 Expr: exprNode, 150 }, 151 }, 152 }, 153 }, 154 } 155 twoFilesUpdatedRuleSet = map[string][]rulefmt.RuleGroup{ 156 "file /one": { 157 { 158 Name: "rulegroup_one", 159 Rules: []rulefmt.RuleNode{ 160 { 161 Record: recordNode, 162 Expr: exprNode, 163 }, 164 }, 165 }, 166 { 167 Name: "rulegroup_two", 168 Rules: []rulefmt.RuleNode{ 169 { 170 Record: recordNode, 171 Expr: exprNode, 172 }, 173 }, 174 }, 175 }, 176 "file /two": { 177 { 178 Name: "rulegroup_one", 179 Rules: []rulefmt.RuleNode{ 180 { 181 Record: recordNodeUpdated, 182 Expr: exprNodeUpdated, 183 }, 184 }, 185 }, 186 }, 187 } 188 twoFilesDeletedRuleSet = map[string][]rulefmt.RuleGroup{ 189 "file /one": { 190 { 191 Name: "rulegroup_one", 192 Rules: []rulefmt.RuleNode{ 193 { 194 Record: recordNode, 195 Expr: exprNode, 196 }, 197 }, 198 }, 199 { 200 Name: "rulegroup_two", 201 Rules: []rulefmt.RuleNode{ 202 { 203 Record: recordNode, 204 Expr: exprNode, 205 }, 206 }, 207 }, 208 }, 209 } 210 specialCharactersRuleSet = map[string][]rulefmt.RuleGroup{ 211 specialCharFile: { 212 { 213 Name: "rulegroup_one", 214 Rules: []rulefmt.RuleNode{ 215 { 216 Record: recordNode, 217 Expr: exprNode, 218 }, 219 }, 220 }, 221 }, 222 } 223 } 224 225 func Test_mapper_MapRules(t *testing.T) { 226 l := log.NewLogfmtLogger(os.Stdout) 227 l = level.NewFilter(l, level.AllowInfo()) 228 setupRuleSets() 229 m := &mapper{ 230 Path: "/rules", 231 FS: afero.NewMemMapFs(), 232 logger: l, 233 } 234 235 t.Run("basic rulegroup", func(t *testing.T) { 236 updated, files, err := m.MapRules(testUser, initialRuleSet) 237 require.True(t, updated) 238 require.Len(t, files, 1) 239 require.Equal(t, fileOnePath, files[0]) 240 require.NoError(t, err) 241 242 exists, err := afero.Exists(m.FS, fileOnePath) 243 require.True(t, exists) 244 require.NoError(t, err) 245 }) 246 247 t.Run("identical rulegroup", func(t *testing.T) { 248 updated, files, err := m.MapRules(testUser, initialRuleSet) 249 require.False(t, updated) 250 require.Len(t, files, 1) 251 require.NoError(t, err) 252 253 exists, err := afero.Exists(m.FS, fileOnePath) 254 require.True(t, exists) 255 require.NoError(t, err) 256 }) 257 258 t.Run("out of order identical rulegroup", func(t *testing.T) { 259 updated, files, err := m.MapRules(testUser, outOfOrderRuleSet) 260 require.False(t, updated) 261 require.Len(t, files, 1) 262 require.NoError(t, err) 263 264 exists, err := afero.Exists(m.FS, fileOnePath) 265 require.True(t, exists) 266 require.NoError(t, err) 267 }) 268 269 t.Run("updated rulegroup", func(t *testing.T) { 270 updated, files, err := m.MapRules(testUser, updatedRuleSet) 271 require.True(t, updated) 272 require.Len(t, files, 1) 273 require.Equal(t, fileOnePath, files[0]) 274 require.NoError(t, err) 275 276 exists, err := afero.Exists(m.FS, fileOnePath) 277 require.True(t, exists) 278 require.NoError(t, err) 279 }) 280 } 281 282 func Test_mapper_MapRulesMultipleFiles(t *testing.T) { 283 l := log.NewLogfmtLogger(os.Stdout) 284 l = level.NewFilter(l, level.AllowInfo()) 285 setupRuleSets() 286 m := &mapper{ 287 Path: "/rules", 288 FS: afero.NewMemMapFs(), 289 logger: l, 290 } 291 292 t.Run("basic rulegroup", func(t *testing.T) { 293 updated, files, err := m.MapRules(testUser, initialRuleSet) 294 require.True(t, updated) 295 require.Len(t, files, 1) 296 require.Equal(t, fileOnePath, files[0]) 297 require.NoError(t, err) 298 299 exists, err := afero.Exists(m.FS, fileOnePath) 300 require.True(t, exists) 301 require.NoError(t, err) 302 }) 303 304 t.Run("add a file", func(t *testing.T) { 305 updated, files, err := m.MapRules(testUser, twoFilesRuleSet) 306 require.True(t, updated) 307 require.Len(t, files, 2) 308 require.True(t, sliceContains(t, fileOnePath, files)) 309 require.True(t, sliceContains(t, fileTwoPath, files)) 310 require.NoError(t, err) 311 312 exists, err := afero.Exists(m.FS, fileOnePath) 313 require.True(t, exists) 314 require.NoError(t, err) 315 exists, err = afero.Exists(m.FS, fileTwoPath) 316 require.True(t, exists) 317 require.NoError(t, err) 318 }) 319 320 t.Run("update one file", func(t *testing.T) { 321 updated, files, err := m.MapRules(testUser, twoFilesUpdatedRuleSet) 322 require.True(t, updated) 323 require.Len(t, files, 2) 324 require.True(t, sliceContains(t, fileOnePath, files)) 325 require.True(t, sliceContains(t, fileTwoPath, files)) 326 require.NoError(t, err) 327 328 exists, err := afero.Exists(m.FS, fileOnePath) 329 require.True(t, exists) 330 require.NoError(t, err) 331 exists, err = afero.Exists(m.FS, fileTwoPath) 332 require.True(t, exists) 333 require.NoError(t, err) 334 }) 335 336 t.Run("delete one file", func(t *testing.T) { 337 updated, files, err := m.MapRules(testUser, twoFilesDeletedRuleSet) 338 require.True(t, updated) 339 require.Len(t, files, 1) 340 require.Equal(t, fileOnePath, files[0]) 341 require.NoError(t, err) 342 343 exists, err := afero.Exists(m.FS, fileOnePath) 344 require.True(t, exists) 345 require.NoError(t, err) 346 exists, err = afero.Exists(m.FS, fileTwoPath) 347 require.False(t, exists) 348 require.NoError(t, err) 349 }) 350 351 } 352 353 func Test_mapper_MapRulesSpecialCharNamespace(t *testing.T) { 354 l := log.NewLogfmtLogger(os.Stdout) 355 l = level.NewFilter(l, level.AllowInfo()) 356 setupRuleSets() 357 m := &mapper{ 358 Path: "/rules", 359 FS: afero.NewMemMapFs(), 360 logger: l, 361 } 362 363 t.Run("create special characters rulegroup", func(t *testing.T) { 364 updated, files, err := m.MapRules(testUser, specialCharactersRuleSet) 365 require.NoError(t, err) 366 require.True(t, updated) 367 require.Len(t, files, 1) 368 require.Equal(t, specialCharFilePath, files[0]) 369 370 exists, err := afero.Exists(m.FS, specialCharFilePath) 371 require.NoError(t, err) 372 require.True(t, exists) 373 }) 374 375 t.Run("delete special characters rulegroup", func(t *testing.T) { 376 updated, files, err := m.MapRules(testUser, map[string][]rulefmt.RuleGroup{}) 377 require.NoError(t, err) 378 require.True(t, updated) 379 require.Len(t, files, 0) 380 381 exists, err := afero.Exists(m.FS, specialCharFilePath) 382 require.NoError(t, err) 383 require.False(t, exists) 384 }) 385 } 386 387 func sliceContains(t *testing.T, find string, in []string) bool { 388 t.Helper() 389 390 for _, s := range in { 391 if find == s { 392 return true 393 } 394 } 395 396 return false 397 }