// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see .
package event
import (
	"context"
	"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) {
	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(context.Background())
	targetList2 := NewTargetList(context.Background())
	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) {
	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) {
	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:*
	  
	
	`)
	dataCase5 := []byte(``)
	testCases := []struct {
		data      []byte
		expectErr bool
	}{
		{dataCase1, false},
		{dataCase2, false},
		{dataCase3, false},
		{dataCase4, true},
		// make sure we don't fail when queue is empty.
		{dataCase5, false},
	}
	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) {
	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(context.Background())
	targetList2 := NewTargetList(context.Background())
	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) {
	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) {
	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(context.Background())
	targetList2 := NewTargetList(context.Background())
	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)
		}
	}
}