/*
* Minio Cloud Storage, (C) 2018 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package event
import (
"encoding/xml"
"reflect"
"strings"
"testing"
)
func TestValidateFilterRuleValue(t *testing.T) {
testCases := []struct {
value string
expectErr bool
}{
{"foo/.", true},
{"../foo", true},
{`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},
{string([]byte{0xff, 0xfe, 0xfd}), true},
{`foo\bar`, true},
{"Hello/世界", false},
}
for i, testCase := range testCases {
err := ValidateFilterRuleValue(testCase.value)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func TestFilterRuleUnmarshalXML(t *testing.T) {
testCases := []struct {
data []byte
expectedResult *FilterRule
expectErr bool
}{
{[]byte(``), nil, true},
{[]byte(``), nil, true},
{[]byte(``), nil, true},
{[]byte(``), nil, true},
{[]byte(`PrefixHello/世界`), nil, true},
{[]byte(`endsfoo/bar`), nil, true},
{[]byte(`prefixHello/世界`), &FilterRule{"prefix", "Hello/世界"}, false},
{[]byte(`suffixfoo/bar`), &FilterRule{"suffix", "foo/bar"}, false},
}
for i, testCase := range testCases {
result := &FilterRule{}
err := xml.Unmarshal(testCase.data, result)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
}
func TestFilterRuleListUnmarshalXML(t *testing.T) {
testCases := []struct {
data []byte
expectedResult *FilterRuleList
expectErr bool
}{
{[]byte(`suffixHello/世界suffixfoo/bar`), nil, true},
{[]byte(`prefixHello/世界prefixfoo/bar`), nil, true},
{[]byte(`prefixHello/世界`), &FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}}}, false},
{[]byte(`suffixfoo/bar`), &FilterRuleList{[]FilterRule{{"suffix", "foo/bar"}}}, false},
{[]byte(`prefixHello/世界suffixfoo/bar`), &FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}, {"suffix", "foo/bar"}}}, false},
}
for i, testCase := range testCases {
result := &FilterRuleList{}
err := xml.Unmarshal(testCase.data, result)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
}
func TestFilterRuleListPattern(t *testing.T) {
testCases := []struct {
filterRuleList FilterRuleList
expectedResult string
}{
{FilterRuleList{}, ""},
{FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}}}, "Hello/世界*"},
{FilterRuleList{[]FilterRule{{"suffix", "foo/bar"}}}, "*foo/bar"},
{FilterRuleList{[]FilterRule{{"prefix", "Hello/世界"}, {"suffix", "foo/bar"}}}, "Hello/世界*foo/bar"},
}
for i, testCase := range testCases {
result := testCase.filterRuleList.Pattern()
if result != testCase.expectedResult {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestQueueUnmarshalXML(t *testing.T) {
dataCase1 := []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
dataCase2 := []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
dataCase3 := []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
s3:ObjectCreated:Put
`)
testCases := []struct {
data []byte
expectErr bool
}{
{dataCase1, false},
{dataCase2, false},
{dataCase3, true},
}
for i, testCase := range testCases {
err := xml.Unmarshal(testCase.data, &Queue{})
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func TestQueueValidate(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
queue1 := &Queue{}
if err := xml.Unmarshal(data, queue1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
queue2 := &Queue{}
if err := xml.Unmarshal(data, queue2); err != nil {
panic(err)
}
data = []byte(`
1
arn:minio:sqs:eu-west-2:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
queue3 := &Queue{}
if err := xml.Unmarshal(data, queue3); err != nil {
panic(err)
}
targetList1 := NewTargetList()
targetList2 := NewTargetList()
if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil {
panic(err)
}
testCases := []struct {
queue *Queue
region string
targetList *TargetList
expectErr bool
}{
{queue1, "eu-west-1", nil, true},
{queue2, "us-east-1", targetList1, true},
{queue3, "", targetList2, false},
{queue2, "us-east-1", targetList2, false},
}
for i, testCase := range testCases {
err := testCase.queue.Validate(testCase.region, testCase.targetList)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func TestQueueSetRegion(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
queue1 := &Queue{}
if err := xml.Unmarshal(data, queue1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs::1:webhook
s3:ObjectCreated:Put
`)
queue2 := &Queue{}
if err := xml.Unmarshal(data, queue2); err != nil {
panic(err)
}
testCases := []struct {
queue *Queue
region string
expectedResult ARN
}{
{queue1, "eu-west-1", ARN{TargetID{"1", "webhook"}, "eu-west-1"}},
{queue1, "", ARN{TargetID{"1", "webhook"}, ""}},
{queue2, "us-east-1", ARN{TargetID{"1", "webhook"}, "us-east-1"}},
{queue2, "", ARN{TargetID{"1", "webhook"}, ""}},
}
for i, testCase := range testCases {
testCase.queue.SetRegion(testCase.region)
result := testCase.queue.ARN
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestQueueToRulesMap(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
queueCase1 := &Queue{}
if err := xml.Unmarshal(data, queueCase1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
queueCase2 := &Queue{}
if err := xml.Unmarshal(data, queueCase2); err != nil {
panic(err)
}
rulesMapCase1 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"})
rulesMapCase2 := NewRulesMap([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"1", "webhook"})
testCases := []struct {
queue *Queue
expectedResult RulesMap
}{
{queueCase1, rulesMapCase1},
{queueCase2, rulesMapCase2},
}
for i, testCase := range testCases {
result := testCase.queue.ToRulesMap()
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestConfigUnmarshalXML(t *testing.T) {
dataCase1 := []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
dataCase2 := []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
dataCase3 := []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
2
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
dataCase4 := []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
1
suffix
.jpg
arn:aws:lambda:us-west-2:444455556666:cloud-function-A
s3:ObjectCreated:Put
arn:aws:sns:us-west-2:444455556666:sns-notification-one
s3:ObjectCreated:*
`)
testCases := []struct {
data []byte
expectErr bool
}{
{dataCase1, false},
{dataCase2, false},
{dataCase3, false},
{dataCase4, true},
}
for i, testCase := range testCases {
err := xml.Unmarshal(testCase.data, &Config{})
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func TestConfigValidate(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
config1 := &Config{}
if err := xml.Unmarshal(data, config1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
config2 := &Config{}
if err := xml.Unmarshal(data, config2); err != nil {
panic(err)
}
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
2
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
config3 := &Config{}
if err := xml.Unmarshal(data, config3); err != nil {
panic(err)
}
targetList1 := NewTargetList()
targetList2 := NewTargetList()
if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil {
panic(err)
}
testCases := []struct {
config *Config
region string
targetList *TargetList
expectErr bool
}{
{config1, "eu-west-1", nil, true},
{config2, "us-east-1", targetList1, true},
{config3, "", targetList2, false},
{config2, "us-east-1", targetList2, false},
}
for i, testCase := range testCases {
err := testCase.config.Validate(testCase.region, testCase.targetList)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func TestConfigSetRegion(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
config1 := &Config{}
if err := xml.Unmarshal(data, config1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs::1:webhook
s3:ObjectCreated:Put
`)
config2 := &Config{}
if err := xml.Unmarshal(data, config2); err != nil {
panic(err)
}
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
2
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:2:amqp
s3:ObjectCreated:Put
`)
config3 := &Config{}
if err := xml.Unmarshal(data, config3); err != nil {
panic(err)
}
testCases := []struct {
config *Config
region string
expectedResult []ARN
}{
{config1, "eu-west-1", []ARN{{TargetID{"1", "webhook"}, "eu-west-1"}}},
{config1, "", []ARN{{TargetID{"1", "webhook"}, ""}}},
{config2, "us-east-1", []ARN{{TargetID{"1", "webhook"}, "us-east-1"}}},
{config2, "", []ARN{{TargetID{"1", "webhook"}, ""}}},
{config3, "us-east-1", []ARN{{TargetID{"1", "webhook"}, "us-east-1"}, {TargetID{"2", "amqp"}, "us-east-1"}}},
{config3, "", []ARN{{TargetID{"1", "webhook"}, ""}, {TargetID{"2", "amqp"}, ""}}},
}
for i, testCase := range testCases {
testCase.config.SetRegion(testCase.region)
result := []ARN{}
for _, queue := range testCase.config.QueueList {
result = append(result, queue.ARN)
}
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestConfigToRulesMap(t *testing.T) {
var data []byte
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
config1 := &Config{}
if err := xml.Unmarshal(data, config1); err != nil {
panic(err)
}
data = []byte(`
1
prefix
images/
suffix
jpg
arn:minio:sqs::1:webhook
s3:ObjectCreated:Put
`)
config2 := &Config{}
if err := xml.Unmarshal(data, config2); err != nil {
panic(err)
}
data = []byte(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
2
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:2:amqp
s3:ObjectCreated:Put
`)
config3 := &Config{}
if err := xml.Unmarshal(data, config3); err != nil {
panic(err)
}
rulesMapCase1 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"})
rulesMapCase2 := NewRulesMap([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"1", "webhook"})
rulesMapCase3 := NewRulesMap([]Name{ObjectAccessedAll, ObjectCreatedAll, ObjectRemovedAll}, "*", TargetID{"1", "webhook"})
rulesMapCase3.add([]Name{ObjectCreatedPut}, "images/*jpg", TargetID{"2", "amqp"})
testCases := []struct {
config *Config
expectedResult RulesMap
}{
{config1, rulesMapCase1},
{config2, rulesMapCase2},
{config3, rulesMapCase3},
}
for i, testCase := range testCases {
result := testCase.config.ToRulesMap()
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("test %v: data: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestParseConfig(t *testing.T) {
reader1 := strings.NewReader(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
`)
reader2 := strings.NewReader(`
1
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
reader3 := strings.NewReader(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
2
prefix
images/
suffix
jpg
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectCreated:Put
`)
reader4 := strings.NewReader(`
1
arn:minio:sqs:us-east-1:1:webhook
s3:ObjectAccessed:*
s3:ObjectCreated:*
s3:ObjectRemoved:*
1
suffix
.jpg
arn:aws:lambda:us-west-2:444455556666:cloud-function-A
s3:ObjectCreated:Put
arn:aws:sns:us-west-2:444455556666:sns-notification-one
s3:ObjectCreated:*
`)
targetList1 := NewTargetList()
targetList2 := NewTargetList()
if err := targetList2.Add(&ExampleTarget{TargetID{"1", "webhook"}, false, false}); err != nil {
panic(err)
}
testCases := []struct {
reader *strings.Reader
region string
targetList *TargetList
expectErr bool
}{
{reader1, "eu-west-1", nil, true},
{reader2, "us-east-1", targetList1, true},
{reader4, "us-east-1", targetList1, true},
{reader3, "", targetList2, false},
{reader2, "us-east-1", targetList2, false},
}
for i, testCase := range testCases {
if _, err := testCase.reader.Seek(0, 0); err != nil {
panic(err)
}
_, err := ParseConfig(testCase.reader, testCase.region, testCase.targetList)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}