mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 08:21:27 +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))
 | |
| 	}
 | |
| }
 |