mirror of
				https://github.com/traefik/traefik.git
				synced 2025-11-04 10:21:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			300 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package rules
 | 
						|
 | 
						|
import (
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
// testTree = Tree + CheckErr
 | 
						|
type testTree struct {
 | 
						|
	Matcher   string
 | 
						|
	Not       bool
 | 
						|
	Value     []string
 | 
						|
	RuleLeft  *testTree
 | 
						|
	RuleRight *testTree
 | 
						|
 | 
						|
	// CheckErr allow knowing if a Tree has a rule error.
 | 
						|
	CheckErr bool
 | 
						|
}
 | 
						|
 | 
						|
func TestRuleMatch(t *testing.T) {
 | 
						|
	matchers := []string{"m"}
 | 
						|
	testCases := []struct {
 | 
						|
		desc           string
 | 
						|
		rule           string
 | 
						|
		tree           testTree
 | 
						|
		matchers       []string
 | 
						|
		values         []string
 | 
						|
		expectParseErr bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			desc:           "No rule",
 | 
						|
			rule:           "",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "No matcher in rule",
 | 
						|
			rule:           "m",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "No value in rule",
 | 
						|
			rule: "m()",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "m",
 | 
						|
				Value:    []string{},
 | 
						|
				CheckErr: true,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Empty value in rule",
 | 
						|
			rule: "m(``)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "m",
 | 
						|
				Value:    []string{""},
 | 
						|
				CheckErr: true,
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{""},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "One value in rule with and",
 | 
						|
			rule:           "m(`1`) &&",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "One value in rule with or",
 | 
						|
			rule:           "m(`1`) ||",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "One value in rule with missing back tick",
 | 
						|
			rule:           "m(`1)",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "One value in rule with missing opening parenthesis",
 | 
						|
			rule:           "m(`1`))",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "One value in rule with missing closing parenthesis",
 | 
						|
			rule:           "(m(`1`)",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "One value in rule",
 | 
						|
			rule: "m(`1`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Value:   []string{"1"},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "One value in rule with superfluous parenthesis",
 | 
						|
			rule: "(m(`1`))",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Value:   []string{"1"},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Rule with CAPS matcher",
 | 
						|
			rule: "M(`1`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Value:   []string{"1"},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc:           "Invalid matcher in rule",
 | 
						|
			rule:           "w(`1`)",
 | 
						|
			expectParseErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Invalid matchers",
 | 
						|
			rule: "m(`1`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Value:   []string{"1"},
 | 
						|
			},
 | 
						|
			matchers: []string{"not-m"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Two value in rule",
 | 
						|
			rule: "m(`1`, `2`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Value:   []string{"1", "2"},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1", "2"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Not one value in rule",
 | 
						|
			rule: "!m(`1`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher: "m",
 | 
						|
				Not:     true,
 | 
						|
				Value:   []string{"1"},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Two value in rule with and",
 | 
						|
			rule: "m(`1`) && m(`2`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "and",
 | 
						|
				CheckErr: true,
 | 
						|
				RuleLeft: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Value:   []string{"1"},
 | 
						|
				},
 | 
						|
				RuleRight: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Value:   []string{"2"},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1", "2"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Two value in rule with or",
 | 
						|
			rule: "m(`1`) || m(`2`)",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "or",
 | 
						|
				CheckErr: true,
 | 
						|
				RuleLeft: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Value:   []string{"1"},
 | 
						|
				},
 | 
						|
				RuleRight: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Value:   []string{"2"},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1", "2"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Two value in rule with and negated",
 | 
						|
			rule: "!(m(`1`) && m(`2`))",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "or",
 | 
						|
				CheckErr: true,
 | 
						|
				RuleLeft: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Not:     true,
 | 
						|
					Value:   []string{"1"},
 | 
						|
				},
 | 
						|
				RuleRight: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Not:     true,
 | 
						|
					Value:   []string{"2"},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1", "2"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Two value in rule with or negated",
 | 
						|
			rule: "!(m(`1`) || m(`2`))",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "and",
 | 
						|
				CheckErr: true,
 | 
						|
				RuleLeft: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Not:     true,
 | 
						|
					Value:   []string{"1"},
 | 
						|
				},
 | 
						|
				RuleRight: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Not:     true,
 | 
						|
					Value:   []string{"2"},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1", "2"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "No value in rule",
 | 
						|
			rule: "m(`1`) && m()",
 | 
						|
			tree: testTree{
 | 
						|
				Matcher:  "and",
 | 
						|
				CheckErr: true,
 | 
						|
				RuleLeft: &testTree{
 | 
						|
					Matcher: "m",
 | 
						|
					Value:   []string{"1"},
 | 
						|
				},
 | 
						|
				RuleRight: &testTree{
 | 
						|
					Matcher:  "m",
 | 
						|
					Value:    []string{},
 | 
						|
					CheckErr: true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			matchers: []string{"m"},
 | 
						|
			values:   []string{"1"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	parser, err := NewParser(matchers)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	for _, test := range testCases {
 | 
						|
		t.Run(test.desc, func(t *testing.T) {
 | 
						|
			t.Parallel()
 | 
						|
 | 
						|
			parse, err := parser.Parse(test.rule)
 | 
						|
			if test.expectParseErr {
 | 
						|
				require.Error(t, err)
 | 
						|
				return
 | 
						|
			}
 | 
						|
			require.NoError(t, err)
 | 
						|
 | 
						|
			treeBuilder, ok := parse.(TreeBuilder)
 | 
						|
			require.True(t, ok)
 | 
						|
 | 
						|
			tree := treeBuilder()
 | 
						|
			checkEquivalence(t, &test.tree, tree)
 | 
						|
 | 
						|
			assert.Equal(t, test.values, tree.ParseMatchers(test.matchers))
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func checkEquivalence(t *testing.T, expected *testTree, actual *Tree) {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	if actual == nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if actual.RuleLeft != nil {
 | 
						|
		checkEquivalence(t, expected.RuleLeft, actual.RuleLeft)
 | 
						|
	}
 | 
						|
 | 
						|
	if actual.RuleRight != nil {
 | 
						|
		checkEquivalence(t, expected.RuleRight, actual.RuleRight)
 | 
						|
	}
 | 
						|
 | 
						|
	assert.Equal(t, expected.Matcher, actual.Matcher)
 | 
						|
	assert.Equal(t, expected.Not, actual.Not)
 | 
						|
	assert.Equal(t, expected.Value, actual.Value)
 | 
						|
 | 
						|
	t.Logf("%+v -> %v", actual, CheckRule(actual))
 | 
						|
	if expected.CheckErr {
 | 
						|
		assert.Error(t, CheckRule(actual))
 | 
						|
	} else {
 | 
						|
		assert.NoError(t, CheckRule(actual))
 | 
						|
	}
 | 
						|
}
 |