// Copyright 2018 Palantir Technologies, 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 approval import ( "reflect" "testing" "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common" ) func TestParsePolicy(t *testing.T) { policyText := ` - rule1 - rule2 - or: - and: - rule3 - rule4 - rule5 - and: - rule6 - rule7 ` ruleText := ` - name: rule1 options: allow_author: true - name: rule2 options: allow_author: true allow_contributor: true - name: rule3 options: allow_author: true allow_contributor: true # invalidate_on_push: true - name: rule4 options: allow_author: true # invalidate_on_push: true - name: rule5 options: allow_contributor: true # invalidate_on_push: true - name: rule6 options: allow_contributor: true - name: rule7 options: request_review: enabled: true requires: admins: true ` var policy Policy err := yaml.UnmarshalStrict([]byte(policyText), &policy) require.NoError(t, err, "failed to unmarshal policy") var rules []*Rule err = yaml.UnmarshalStrict([]byte(ruleText), &rules) require.NoError(t, err, "failed to unmarshal rules") rulesByName := make(map[string]*Rule) for _, r := range rules { rulesByName[r.Name] = r } req, err := policy.Parse(rulesByName) require.NoError(t, err, "failed to parse policy") expected := &evaluator{ root: &AndRequirement{ requirements: []common.Evaluator{ &RuleRequirement{ rule: rules[0], }, &RuleRequirement{ rule: rules[1], }, &OrRequirement{ requirements: []common.Evaluator{ &AndRequirement{ requirements: []common.Evaluator{ &RuleRequirement{ rule: rules[2], }, &RuleRequirement{ rule: rules[3], }, }, }, &RuleRequirement{ rule: rules[4], }, }, }, &AndRequirement{ requirements: []common.Evaluator{ &RuleRequirement{ rule: rules[5], }, &RuleRequirement{ rule: rules[6], }, }, }, }, }, } require.True(t, reflect.DeepEqual(expected, req)) } func TestParsePolicyError_empty(t *testing.T) { // Empty list policy := ` - rule1 - or: [] ` rules := ` - name: rule1 ` _, err := loadAndParsePolicy(t, policy, rules) require.Error(t, err) } func TestParsePolicyError_unknownRule(t *testing.T) { // Non-existing rule policy := ` - rule1 ` rules := ` - name: rule2 ` _, err := loadAndParsePolicy(t, policy, rules) require.Error(t, err) } func TestParsePolicyError_illegalType(t *testing.T) { // Illegal type policy := ` - or: - rule1 - [a, b] ` rules := ` - name: rule1 ` _, err := loadAndParsePolicy(t, policy, rules) require.Error(t, err) } func TestParsePolicyError_multikey(t *testing.T) { // Multiple keys policy := ` - or: - rule1 and: - rule1 ` rules := ` - name: rule1 ` _, err := loadAndParsePolicy(t, policy, rules) require.Error(t, err) } func TestParsePolicyError_recursiveDepth(t *testing.T) { // Recursive depth 10 is allowed policy := ` - or: - or: - or: - or: - or: - or: - or: - or: - or: - rule1 ` rules := ` - name: rule1 ` _, err := loadAndParsePolicy(t, policy, rules) require.NoError(t, err) // Recursive depth 11 is not allowed policy = ` - or: - or: - or: - or: - or: - or: - or: - or: - or: - or: - rule1 ` _, err = loadAndParsePolicy(t, policy, rules) require.Error(t, err) } func loadAndParsePolicy(t *testing.T, policyText string, ruleText string) (common.Evaluator, error) { var policy Policy err := yaml.UnmarshalStrict([]byte(policyText), &policy) require.NoError(t, err, "failed to unmarshal policy") var rules []*Rule err = yaml.UnmarshalStrict([]byte(ruleText), &rules) require.NoError(t, err, "failed to unmarshal rules") rulesByName := make(map[string]*Rule) for _, r := range rules { rulesByName[r.Name] = r } return policy.Parse(rulesByName) }