github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/event/config_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package event 19 20 import ( 21 "context" 22 "encoding/xml" 23 "reflect" 24 "strings" 25 "testing" 26 ) 27 28 func TestValidateFilterRuleValue(t *testing.T) { 29 testCases := []struct { 30 value string 31 expectErr bool 32 }{ 33 {"foo/.", true}, 34 {"../foo", true}, 35 {`foo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/bazfoo/bar/baz`, true}, 36 {string([]byte{0xff, 0xfe, 0xfd}), true}, 37 {`foo\bar`, true}, 38 {"Hello/世界", false}, 39 } 40 41 for i, testCase := range testCases { 42 err := ValidateFilterRuleValue(testCase.value) 43 expectErr := (err != nil) 44 45 if expectErr != testCase.expectErr { 46 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 47 } 48 } 49 } 50 51 func TestFilterRuleUnmarshalXML(t *testing.T) { 52 testCases := []struct { 53 data []byte 54 expectedResult *FilterRule 55 expectErr bool 56 }{ 57 {[]byte(`<FilterRule></FilterRule>`), nil, true}, 58 {[]byte(`<FilterRule><Name></Name></FilterRule>`), nil, true}, 59 {[]byte(`<FilterRule><Value></Value></FilterRule>`), nil, true}, 60 {[]byte(`<FilterRule><Name></Name><Value></Value></FilterRule>`), nil, true}, 61 {[]byte(`<FilterRule><Name>Prefix</Name><Value>Hello/世界</Value></FilterRule>`), nil, true}, 62 {[]byte(`<FilterRule><Name>ends</Name><Value>foo/bar</Value></FilterRule>`), nil, true}, 63 {[]byte(`<FilterRule><Name>prefix</Name><Value>Hello/世界</Value></FilterRule>`), &FilterRule{"prefix", "Hello/世界"}, false}, 64 {[]byte(`<FilterRule><Name>suffix</Name><Value>foo/bar</Value></FilterRule>`), &FilterRule{"suffix", "foo/bar"}, false}, 65 } 66 67 for i, testCase := range testCases { 68 result := &FilterRule{} 69 err := xml.Unmarshal(testCase.data, result) 70 expectErr := (err != nil) 71 72 if expectErr != testCase.expectErr { 73 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 74 } 75 76 if !testCase.expectErr { 77 if !reflect.DeepEqual(result, testCase.expectedResult) { 78 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 79 } 80 } 81 } 82 } 83 84 func TestFilterRuleListUnmarshalXML(t *testing.T) { 85 testCases := []struct { 86 data []byte 87 expectedResult *FilterRuleList 88 expectErr bool 89 }{ 90 {[]byte(`<S3Key><FilterRule><Name>suffix</Name><Value>Hello/世界</Value></FilterRule><FilterRule><Name>suffix</Name><Value>foo/bar</Value></FilterRule></S3Key>`), nil, true}, 91 {[]byte(`<S3Key><FilterRule><Name>prefix</Name><Value>Hello/世界</Value></FilterRule><FilterRule><Name>prefix</Name><Value>foo/bar</Value></FilterRule></S3Key>`), nil, true}, 92 {[]byte(`<S3Key><FilterRule><Name>prefix</Name><Value>Hello/世界</Value></FilterRule></S3Key>`), &FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}}}, false}, 93 {[]byte(`<S3Key><FilterRule><Name>suffix</Name><Value>foo/bar</Value></FilterRule></S3Key>`), &FilterRuleList{[]FilterRule{{"suffix", "foo/bar"}}}, false}, 94 {[]byte(`<S3Key><FilterRule><Name>prefix</Name><Value>Hello/世界</Value></FilterRule><FilterRule><Name>suffix</Name><Value>foo/bar</Value></FilterRule></S3Key>`), &FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}, {"suffix", "foo/bar"}}}, false}, 95 } 96 97 for i, testCase := range testCases { 98 result := &FilterRuleList{} 99 err := xml.Unmarshal(testCase.data, result) 100 expectErr := (err != nil) 101 102 if expectErr != testCase.expectErr { 103 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 104 } 105 106 if !testCase.expectErr { 107 if !reflect.DeepEqual(result, testCase.expectedResult) { 108 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 109 } 110 } 111 } 112 } 113 114 func TestFilterRuleListPattern(t *testing.T) { 115 testCases := []struct { 116 filterRuleList FilterRuleList 117 expectedResult string 118 }{ 119 {FilterRuleList{}, ""}, 120 {FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}}}, "Hello/世界*"}, 121 {FilterRuleList{[]FilterRule{{"suffix", "foo/bar"}}}, "*foo/bar"}, 122 {FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}, {"suffix", "foo/bar"}}}, "Hello/世界*foo/bar"}, 123 } 124 125 for i, testCase := range testCases { 126 result := testCase.filterRuleList.Pattern() 127 128 if result != testCase.expectedResult { 129 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 130 } 131 } 132 } 133 134 func TestQueueUnmarshalXML(t *testing.T) { 135 dataCase1 := []byte(` 136 <QueueConfiguration> 137 <Id>1</Id> 138 <Filter></Filter> 139 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 140 <Event>s3:ObjectAccessed:*</Event> 141 <Event>s3:ObjectCreated:*</Event> 142 <Event>s3:ObjectRemoved:*</Event> 143 </QueueConfiguration>`) 144 145 dataCase2 := []byte(` 146 <QueueConfiguration> 147 <Id>1</Id> 148 <Filter> 149 <S3Key> 150 <FilterRule> 151 <Name>prefix</Name> 152 <Value>images/</Value> 153 </FilterRule> 154 <FilterRule> 155 <Name>suffix</Name> 156 <Value>jpg</Value> 157 </FilterRule> 158 </S3Key> 159 </Filter> 160 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 161 <Event>s3:ObjectCreated:Put</Event> 162 </QueueConfiguration>`) 163 164 dataCase3 := []byte(` 165 <QueueConfiguration> 166 <Id>1</Id> 167 <Filter> 168 <S3Key> 169 <FilterRule> 170 <Name>prefix</Name> 171 <Value>images/</Value> 172 </FilterRule> 173 <FilterRule> 174 <Name>suffix</Name> 175 <Value>jpg</Value> 176 </FilterRule> 177 </S3Key> 178 </Filter> 179 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 180 <Event>s3:ObjectCreated:Put</Event> 181 <Event>s3:ObjectCreated:Put</Event> 182 </QueueConfiguration>`) 183 184 testCases := []struct { 185 data []byte 186 expectErr bool 187 }{ 188 {dataCase1, false}, 189 {dataCase2, false}, 190 {dataCase3, true}, 191 } 192 193 for i, testCase := range testCases { 194 err := xml.Unmarshal(testCase.data, &Queue{}) 195 expectErr := (err != nil) 196 197 if expectErr != testCase.expectErr { 198 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 199 } 200 } 201 } 202 203 func TestQueueValidate(t *testing.T) { 204 data := []byte(` 205 <QueueConfiguration> 206 <Id>1</Id> 207 <Filter></Filter> 208 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 209 <Event>s3:ObjectAccessed:*</Event> 210 <Event>s3:ObjectCreated:*</Event> 211 <Event>s3:ObjectRemoved:*</Event> 212 </QueueConfiguration>`) 213 queue1 := &Queue{} 214 if err := xml.Unmarshal(data, queue1); err != nil { 215 panic(err) 216 } 217 218 data = []byte(` 219 <QueueConfiguration> 220 <Id>1</Id> 221 <Filter> 222 <S3Key> 223 <FilterRule> 224 <Name>prefix</Name> 225 <Value>images/</Value> 226 </FilterRule> 227 <FilterRule> 228 <Name>suffix</Name> 229 <Value>jpg</Value> 230 </FilterRule> 231 </S3Key> 232 </Filter> 233 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 234 <Event>s3:ObjectCreated:Put</Event> 235 </QueueConfiguration>`) 236 queue2 := &Queue{} 237 if err := xml.Unmarshal(data, queue2); err != nil { 238 panic(err) 239 } 240 241 data = []byte(` 242 <QueueConfiguration> 243 <Id>1</Id> 244 <Filter></Filter> 245 <Queue>arn:minio:sqs:eu-west-2:1:webhook</Queue> 246 <Event>s3:ObjectAccessed:*</Event> 247 <Event>s3:ObjectCreated:*</Event> 248 <Event>s3:ObjectRemoved:*</Event> 249 </QueueConfiguration>`) 250 queue3 := &Queue{} 251 if err := xml.Unmarshal(data, queue3); err != nil { 252 panic(err) 253 } 254 255 targetList1 := NewTargetList(context.Background()) 256 257 targetList2 := NewTargetList(context.Background()) 258 if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil { 259 panic(err) 260 } 261 262 testCases := []struct { 263 queue *Queue 264 region string 265 targetList *TargetList 266 expectErr bool 267 }{ 268 {queue1, "eu-west-1", nil, true}, 269 {queue2, "us-east-1", targetList1, true}, 270 {queue3, "", targetList2, false}, 271 {queue2, "us-east-1", targetList2, false}, 272 } 273 274 for i, testCase := range testCases { 275 err := testCase.queue.Validate(testCase.region, testCase.targetList) 276 expectErr := (err != nil) 277 278 if expectErr != testCase.expectErr { 279 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 280 } 281 } 282 } 283 284 func TestQueueSetRegion(t *testing.T) { 285 data := []byte(` 286 <QueueConfiguration> 287 <Id>1</Id> 288 <Filter></Filter> 289 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 290 <Event>s3:ObjectAccessed:*</Event> 291 <Event>s3:ObjectCreated:*</Event> 292 <Event>s3:ObjectRemoved:*</Event> 293 </QueueConfiguration>`) 294 queue1 := &Queue{} 295 if err := xml.Unmarshal(data, queue1); err != nil { 296 panic(err) 297 } 298 299 data = []byte(` 300 <QueueConfiguration> 301 <Id>1</Id> 302 <Filter> 303 <S3Key> 304 <FilterRule> 305 <Name>prefix</Name> 306 <Value>images/</Value> 307 </FilterRule> 308 <FilterRule> 309 <Name>suffix</Name> 310 <Value>jpg</Value> 311 </FilterRule> 312 </S3Key> 313 </Filter> 314 <Queue>arn:minio:sqs::1:webhook</Queue> 315 <Event>s3:ObjectCreated:Put</Event> 316 </QueueConfiguration>`) 317 queue2 := &Queue{} 318 if err := xml.Unmarshal(data, queue2); err != nil { 319 panic(err) 320 } 321 322 testCases := []struct { 323 queue *Queue 324 region string 325 expectedResult ARN 326 }{ 327 {queue1, "eu-west-1", ARN{TargetID{"1", "webhook"}, "eu-west-1"}}, 328 {queue1, "", ARN{TargetID{"1", "webhook"}, ""}}, 329 {queue2, "us-east-1", ARN{TargetID{"1", "webhook"}, "us-east-1"}}, 330 {queue2, "", ARN{TargetID{"1", "webhook"}, ""}}, 331 } 332 333 for i, testCase := range testCases { 334 testCase.queue.SetRegion(testCase.region) 335 result := testCase.queue.ARN 336 337 if !reflect.DeepEqual(result, testCase.expectedResult) { 338 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 339 } 340 } 341 } 342 343 func TestQueueToRulesMap(t *testing.T) { 344 data := []byte(` 345 <QueueConfiguration> 346 <Id>1</Id> 347 <Filter></Filter> 348 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 349 <Event>s3:ObjectAccessed:*</Event> 350 <Event>s3:ObjectCreated:*</Event> 351 <Event>s3:ObjectRemoved:*</Event> 352 </QueueConfiguration>`) 353 queueCase1 := &Queue{} 354 if err := xml.Unmarshal(data, queueCase1); err != nil { 355 panic(err) 356 } 357 358 data = []byte(` 359 <QueueConfiguration> 360 <Id>1</Id> 361 <Filter> 362 <S3Key> 363 <FilterRule> 364 <Name>prefix</Name> 365 <Value>images/</Value> 366 </FilterRule> 367 <FilterRule> 368 <Name>suffix</Name> 369 <Value>jpg</Value> 370 </FilterRule> 371 </S3Key> 372 </Filter> 373 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 374 <Event>s3:ObjectCreated:Put</Event> 375 </QueueConfiguration>`) 376 queueCase2 := &Queue{} 377 if err := xml.Unmarshal(data, queueCase2); err != nil { 378 panic(err) 379 } 380 381 rulesMapCase1 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"}) 382 rulesMapCase2 := NewRulesMap([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"1", "webhook"}) 383 384 testCases := []struct { 385 queue *Queue 386 expectedResult RulesMap 387 }{ 388 {queueCase1, rulesMapCase1}, 389 {queueCase2, rulesMapCase2}, 390 } 391 392 for i, testCase := range testCases { 393 result := testCase.queue.ToRulesMap() 394 395 if !reflect.DeepEqual(result, testCase.expectedResult) { 396 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 397 } 398 } 399 } 400 401 func TestConfigUnmarshalXML(t *testing.T) { 402 dataCase1 := []byte(` 403 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 404 <QueueConfiguration> 405 <Id>1</Id> 406 <Filter></Filter> 407 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 408 <Event>s3:ObjectAccessed:*</Event> 409 <Event>s3:ObjectCreated:*</Event> 410 <Event>s3:ObjectRemoved:*</Event> 411 </QueueConfiguration> 412 </NotificationConfiguration> 413 `) 414 415 dataCase2 := []byte(` 416 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 417 <QueueConfiguration> 418 <Id>1</Id> 419 <Filter> 420 <S3Key> 421 <FilterRule> 422 <Name>prefix</Name> 423 <Value>images/</Value> 424 </FilterRule> 425 <FilterRule> 426 <Name>suffix</Name> 427 <Value>jpg</Value> 428 </FilterRule> 429 </S3Key> 430 </Filter> 431 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 432 <Event>s3:ObjectCreated:Put</Event> 433 </QueueConfiguration> 434 </NotificationConfiguration> 435 `) 436 437 dataCase3 := []byte(` 438 <NotificationConfiguration> 439 <QueueConfiguration> 440 <Id>1</Id> 441 <Filter></Filter> 442 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 443 <Event>s3:ObjectAccessed:*</Event> 444 <Event>s3:ObjectCreated:*</Event> 445 <Event>s3:ObjectRemoved:*</Event> 446 </QueueConfiguration> 447 <QueueConfiguration> 448 <Id>2</Id> 449 <Filter> 450 <S3Key> 451 <FilterRule> 452 <Name>prefix</Name> 453 <Value>images/</Value> 454 </FilterRule> 455 <FilterRule> 456 <Name>suffix</Name> 457 <Value>jpg</Value> 458 </FilterRule> 459 </S3Key> 460 </Filter> 461 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 462 <Event>s3:ObjectCreated:Put</Event> 463 </QueueConfiguration> 464 </NotificationConfiguration> 465 `) 466 467 dataCase4 := []byte(` 468 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 469 <QueueConfiguration> 470 <Id>1</Id> 471 <Filter></Filter> 472 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 473 <Event>s3:ObjectAccessed:*</Event> 474 <Event>s3:ObjectCreated:*</Event> 475 <Event>s3:ObjectRemoved:*</Event> 476 </QueueConfiguration> 477 <CloudFunctionConfiguration> 478 <Id>1</Id> 479 <Filter> 480 <S3Key> 481 <FilterRule> 482 <Name>suffix</Name> 483 <Value>.jpg</Value> 484 </FilterRule> 485 </S3Key> 486 </Filter> 487 <Cloudcode>arn:aws:lambda:us-west-2:444455556666:cloud-function-A</Cloudcode> 488 <Event>s3:ObjectCreated:Put</Event> 489 </CloudFunctionConfiguration> 490 <TopicConfiguration> 491 <Topic>arn:aws:sns:us-west-2:444455556666:sns-notification-one</Topic> 492 <Event>s3:ObjectCreated:*</Event> 493 </TopicConfiguration> 494 </NotificationConfiguration> 495 `) 496 497 dataCase5 := []byte(`<NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/" ></NotificationConfiguration>`) 498 499 testCases := []struct { 500 data []byte 501 expectErr bool 502 }{ 503 {dataCase1, false}, 504 {dataCase2, false}, 505 {dataCase3, false}, 506 {dataCase4, true}, 507 // make sure we don't fail when queue is empty. 508 {dataCase5, false}, 509 } 510 511 for i, testCase := range testCases { 512 err := xml.Unmarshal(testCase.data, &Config{}) 513 expectErr := (err != nil) 514 515 if expectErr != testCase.expectErr { 516 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 517 } 518 } 519 } 520 521 func TestConfigValidate(t *testing.T) { 522 data := []byte(` 523 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 524 <QueueConfiguration> 525 <Id>1</Id> 526 <Filter></Filter> 527 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 528 <Event>s3:ObjectAccessed:*</Event> 529 <Event>s3:ObjectCreated:*</Event> 530 <Event>s3:ObjectRemoved:*</Event> 531 </QueueConfiguration> 532 </NotificationConfiguration> 533 `) 534 config1 := &Config{} 535 if err := xml.Unmarshal(data, config1); err != nil { 536 panic(err) 537 } 538 539 data = []byte(` 540 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 541 <QueueConfiguration> 542 <Id>1</Id> 543 <Filter> 544 <S3Key> 545 <FilterRule> 546 <Name>prefix</Name> 547 <Value>images/</Value> 548 </FilterRule> 549 <FilterRule> 550 <Name>suffix</Name> 551 <Value>jpg</Value> 552 </FilterRule> 553 </S3Key> 554 </Filter> 555 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 556 <Event>s3:ObjectCreated:Put</Event> 557 </QueueConfiguration> 558 </NotificationConfiguration> 559 `) 560 config2 := &Config{} 561 if err := xml.Unmarshal(data, config2); err != nil { 562 panic(err) 563 } 564 565 data = []byte(` 566 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 567 <QueueConfiguration> 568 <Id>1</Id> 569 <Filter></Filter> 570 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 571 <Event>s3:ObjectAccessed:*</Event> 572 <Event>s3:ObjectCreated:*</Event> 573 <Event>s3:ObjectRemoved:*</Event> 574 </QueueConfiguration> 575 <QueueConfiguration> 576 <Id>2</Id> 577 <Filter> 578 <S3Key> 579 <FilterRule> 580 <Name>prefix</Name> 581 <Value>images/</Value> 582 </FilterRule> 583 <FilterRule> 584 <Name>suffix</Name> 585 <Value>jpg</Value> 586 </FilterRule> 587 </S3Key> 588 </Filter> 589 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 590 <Event>s3:ObjectCreated:Put</Event> 591 </QueueConfiguration> 592 </NotificationConfiguration> 593 `) 594 config3 := &Config{} 595 if err := xml.Unmarshal(data, config3); err != nil { 596 panic(err) 597 } 598 599 targetList1 := NewTargetList(context.Background()) 600 601 targetList2 := NewTargetList(context.Background()) 602 if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil { 603 panic(err) 604 } 605 606 testCases := []struct { 607 config *Config 608 region string 609 targetList *TargetList 610 expectErr bool 611 }{ 612 {config1, "eu-west-1", nil, true}, 613 {config2, "us-east-1", targetList1, true}, 614 {config3, "", targetList2, false}, 615 {config2, "us-east-1", targetList2, false}, 616 } 617 618 for i, testCase := range testCases { 619 err := testCase.config.Validate(testCase.region, testCase.targetList) 620 expectErr := (err != nil) 621 622 if expectErr != testCase.expectErr { 623 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 624 } 625 } 626 } 627 628 func TestConfigSetRegion(t *testing.T) { 629 data := []byte(` 630 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 631 <QueueConfiguration> 632 <Id>1</Id> 633 <Filter></Filter> 634 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 635 <Event>s3:ObjectAccessed:*</Event> 636 <Event>s3:ObjectCreated:*</Event> 637 <Event>s3:ObjectRemoved:*</Event> 638 </QueueConfiguration> 639 </NotificationConfiguration> 640 `) 641 config1 := &Config{} 642 if err := xml.Unmarshal(data, config1); err != nil { 643 panic(err) 644 } 645 646 data = []byte(` 647 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 648 <QueueConfiguration> 649 <Id>1</Id> 650 <Filter> 651 <S3Key> 652 <FilterRule> 653 <Name>prefix</Name> 654 <Value>images/</Value> 655 </FilterRule> 656 <FilterRule> 657 <Name>suffix</Name> 658 <Value>jpg</Value> 659 </FilterRule> 660 </S3Key> 661 </Filter> 662 <Queue>arn:minio:sqs::1:webhook</Queue> 663 <Event>s3:ObjectCreated:Put</Event> 664 </QueueConfiguration> 665 </NotificationConfiguration> 666 `) 667 config2 := &Config{} 668 if err := xml.Unmarshal(data, config2); err != nil { 669 panic(err) 670 } 671 672 data = []byte(` 673 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 674 <QueueConfiguration> 675 <Id>1</Id> 676 <Filter></Filter> 677 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 678 <Event>s3:ObjectAccessed:*</Event> 679 <Event>s3:ObjectCreated:*</Event> 680 <Event>s3:ObjectRemoved:*</Event> 681 </QueueConfiguration> 682 <QueueConfiguration> 683 <Id>2</Id> 684 <Filter> 685 <S3Key> 686 <FilterRule> 687 <Name>prefix</Name> 688 <Value>images/</Value> 689 </FilterRule> 690 <FilterRule> 691 <Name>suffix</Name> 692 <Value>jpg</Value> 693 </FilterRule> 694 </S3Key> 695 </Filter> 696 <Queue>arn:minio:sqs:us-east-1:2:amqp</Queue> 697 <Event>s3:ObjectCreated:Put</Event> 698 </QueueConfiguration> 699 </NotificationConfiguration> 700 `) 701 config3 := &Config{} 702 if err := xml.Unmarshal(data, config3); err != nil { 703 panic(err) 704 } 705 706 testCases := []struct { 707 config *Config 708 region string 709 expectedResult []ARN 710 }{ 711 {config1, "eu-west-1", []ARN{{TargetID{"1", "webhook"}, "eu-west-1"}}}, 712 {config1, "", []ARN{{TargetID{"1", "webhook"}, ""}}}, 713 {config2, "us-east-1", []ARN{{TargetID{"1", "webhook"}, "us-east-1"}}}, 714 {config2, "", []ARN{{TargetID{"1", "webhook"}, ""}}}, 715 {config3, "us-east-1", []ARN{{TargetID{"1", "webhook"}, "us-east-1"}, {TargetID{"2", "amqp"}, "us-east-1"}}}, 716 {config3, "", []ARN{{TargetID{"1", "webhook"}, ""}, {TargetID{"2", "amqp"}, ""}}}, 717 } 718 719 for i, testCase := range testCases { 720 testCase.config.SetRegion(testCase.region) 721 result := []ARN{} 722 for _, queue := range testCase.config.QueueList { 723 result = append(result, queue.ARN) 724 } 725 726 if !reflect.DeepEqual(result, testCase.expectedResult) { 727 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 728 } 729 } 730 } 731 732 func TestConfigToRulesMap(t *testing.T) { 733 data := []byte(` 734 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 735 <QueueConfiguration> 736 <Id>1</Id> 737 <Filter></Filter> 738 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 739 <Event>s3:ObjectAccessed:*</Event> 740 <Event>s3:ObjectCreated:*</Event> 741 <Event>s3:ObjectRemoved:*</Event> 742 </QueueConfiguration> 743 </NotificationConfiguration> 744 `) 745 config1 := &Config{} 746 if err := xml.Unmarshal(data, config1); err != nil { 747 panic(err) 748 } 749 750 data = []byte(` 751 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 752 <QueueConfiguration> 753 <Id>1</Id> 754 <Filter> 755 <S3Key> 756 <FilterRule> 757 <Name>prefix</Name> 758 <Value>images/</Value> 759 </FilterRule> 760 <FilterRule> 761 <Name>suffix</Name> 762 <Value>jpg</Value> 763 </FilterRule> 764 </S3Key> 765 </Filter> 766 <Queue>arn:minio:sqs::1:webhook</Queue> 767 <Event>s3:ObjectCreated:Put</Event> 768 </QueueConfiguration> 769 </NotificationConfiguration> 770 `) 771 config2 := &Config{} 772 if err := xml.Unmarshal(data, config2); err != nil { 773 panic(err) 774 } 775 776 data = []byte(` 777 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 778 <QueueConfiguration> 779 <Id>1</Id> 780 <Filter></Filter> 781 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 782 <Event>s3:ObjectAccessed:*</Event> 783 <Event>s3:ObjectCreated:*</Event> 784 <Event>s3:ObjectRemoved:*</Event> 785 </QueueConfiguration> 786 <QueueConfiguration> 787 <Id>2</Id> 788 <Filter> 789 <S3Key> 790 <FilterRule> 791 <Name>prefix</Name> 792 <Value>images/</Value> 793 </FilterRule> 794 <FilterRule> 795 <Name>suffix</Name> 796 <Value>jpg</Value> 797 </FilterRule> 798 </S3Key> 799 </Filter> 800 <Queue>arn:minio:sqs:us-east-1:2:amqp</Queue> 801 <Event>s3:ObjectCreated:Put</Event> 802 </QueueConfiguration> 803 </NotificationConfiguration> 804 `) 805 config3 := &Config{} 806 if err := xml.Unmarshal(data, config3); err != nil { 807 panic(err) 808 } 809 810 rulesMapCase1 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"}) 811 812 rulesMapCase2 := NewRulesMap([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"1", "webhook"}) 813 814 rulesMapCase3 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"}) 815 rulesMapCase3.add([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"2", "amqp"}) 816 817 testCases := []struct { 818 config *Config 819 expectedResult RulesMap 820 }{ 821 {config1, rulesMapCase1}, 822 {config2, rulesMapCase2}, 823 {config3, rulesMapCase3}, 824 } 825 826 for i, testCase := range testCases { 827 result := testCase.config.ToRulesMap() 828 829 if !reflect.DeepEqual(result, testCase.expectedResult) { 830 t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result) 831 } 832 } 833 } 834 835 func TestParseConfig(t *testing.T) { 836 reader1 := strings.NewReader(` 837 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 838 <QueueConfiguration> 839 <Id>1</Id> 840 <Filter></Filter> 841 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 842 <Event>s3:ObjectAccessed:*</Event> 843 <Event>s3:ObjectCreated:*</Event> 844 <Event>s3:ObjectRemoved:*</Event> 845 </QueueConfiguration> 846 </NotificationConfiguration> 847 `) 848 849 reader2 := strings.NewReader(` 850 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 851 <QueueConfiguration> 852 <Id>1</Id> 853 <Filter> 854 <S3Key> 855 <FilterRule> 856 <Name>prefix</Name> 857 <Value>images/</Value> 858 </FilterRule> 859 <FilterRule> 860 <Name>suffix</Name> 861 <Value>jpg</Value> 862 </FilterRule> 863 </S3Key> 864 </Filter> 865 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 866 <Event>s3:ObjectCreated:Put</Event> 867 </QueueConfiguration> 868 </NotificationConfiguration> 869 `) 870 871 reader3 := strings.NewReader(` 872 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 873 <QueueConfiguration> 874 <Id>1</Id> 875 <Filter></Filter> 876 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 877 <Event>s3:ObjectAccessed:*</Event> 878 <Event>s3:ObjectCreated:*</Event> 879 <Event>s3:ObjectRemoved:*</Event> 880 </QueueConfiguration> 881 <QueueConfiguration> 882 <Id>2</Id> 883 <Filter> 884 <S3Key> 885 <FilterRule> 886 <Name>prefix</Name> 887 <Value>images/</Value> 888 </FilterRule> 889 <FilterRule> 890 <Name>suffix</Name> 891 <Value>jpg</Value> 892 </FilterRule> 893 </S3Key> 894 </Filter> 895 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 896 <Event>s3:ObjectCreated:Put</Event> 897 </QueueConfiguration> 898 </NotificationConfiguration> 899 `) 900 901 reader4 := strings.NewReader(` 902 <NotificationConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 903 <QueueConfiguration> 904 <Id>1</Id> 905 <Filter></Filter> 906 <Queue>arn:minio:sqs:us-east-1:1:webhook</Queue> 907 <Event>s3:ObjectAccessed:*</Event> 908 <Event>s3:ObjectCreated:*</Event> 909 <Event>s3:ObjectRemoved:*</Event> 910 </QueueConfiguration> 911 <CloudFunctionConfiguration> 912 <Id>1</Id> 913 <Filter> 914 <S3Key> 915 <FilterRule> 916 <Name>suffix</Name> 917 <Value>.jpg</Value> 918 </FilterRule> 919 </S3Key> 920 </Filter> 921 <Cloudcode>arn:aws:lambda:us-west-2:444455556666:cloud-function-A</Cloudcode> 922 <Event>s3:ObjectCreated:Put</Event> 923 </CloudFunctionConfiguration> 924 <TopicConfiguration> 925 <Topic>arn:aws:sns:us-west-2:444455556666:sns-notification-one</Topic> 926 <Event>s3:ObjectCreated:*</Event> 927 </TopicConfiguration> 928 </NotificationConfiguration> 929 `) 930 931 targetList1 := NewTargetList(context.Background()) 932 933 targetList2 := NewTargetList(context.Background()) 934 if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil { 935 panic(err) 936 } 937 938 testCases := []struct { 939 reader *strings.Reader 940 region string 941 targetList *TargetList 942 expectErr bool 943 }{ 944 {reader1, "eu-west-1", nil, true}, 945 {reader2, "us-east-1", targetList1, true}, 946 {reader4, "us-east-1", targetList1, true}, 947 {reader3, "", targetList2, false}, 948 {reader2, "us-east-1", targetList2, false}, 949 } 950 951 for i, testCase := range testCases { 952 if _, err := testCase.reader.Seek(0, 0); err != nil { 953 panic(err) 954 } 955 _, err := ParseConfig(testCase.reader, testCase.region, testCase.targetList) 956 expectErr := (err != nil) 957 958 if expectErr != testCase.expectErr { 959 t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 960 } 961 } 962 }