github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/testhelpers/match_plan_matcher.go (about)

     1  package testhelpers
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  	"github.com/onsi/gomega"
    10  	"github.com/onsi/gomega/types"
    11  )
    12  
    13  type PlanMatcher struct {
    14  	ExpectedPlan atc.Plan
    15  
    16  	failedMatcher types.GomegaMatcher
    17  	failedValue   interface{}
    18  }
    19  
    20  func MatchPlan(plan atc.Plan) *PlanMatcher {
    21  	return &PlanMatcher{
    22  		ExpectedPlan: plan,
    23  	}
    24  }
    25  
    26  func VerifyPlan(expectedPlan atc.Plan) http.HandlerFunc {
    27  	return func(w http.ResponseWriter, r *http.Request) {
    28  		var plan atc.Plan
    29  		err := json.NewDecoder(r.Body).Decode(&plan)
    30  		gomega.Expect(err).ToNot(gomega.HaveOccurred())
    31  
    32  		gomega.Expect(plan).To(MatchPlan(expectedPlan))
    33  	}
    34  }
    35  
    36  func (matcher *PlanMatcher) Match(actual interface{}) (bool, error) {
    37  	actualPlan, ok := actual.(atc.Plan)
    38  	if !ok {
    39  		return false, fmt.Errorf("expected a %T, got a %T", matcher.ExpectedPlan, actual)
    40  	}
    41  
    42  	expectedStripped, _ := stripIDs(matcher.ExpectedPlan)
    43  	actualStripped, actualIDs := stripIDs(actualPlan)
    44  
    45  	planMatcher := gomega.Equal(expectedStripped)
    46  
    47  	if !idsAreUnique(actualIDs) {
    48  		return false, fmt.Errorf("expected %#v to contain unique elements", actualIDs)
    49  	}
    50  
    51  	matched, err := planMatcher.Match(actualStripped)
    52  	if err != nil {
    53  		return false, err
    54  	}
    55  
    56  	if !matched {
    57  		matcher.failedMatcher = planMatcher
    58  		matcher.failedValue = actualStripped
    59  		return false, nil
    60  	}
    61  
    62  	return true, nil
    63  }
    64  
    65  func idsAreUnique(ids []string) bool {
    66  	seenIds := make(map[string]bool)
    67  
    68  	for _, id := range ids {
    69  		if seenIds[id] {
    70  			return false
    71  		}
    72  
    73  		seenIds[id] = true
    74  	}
    75  
    76  	return true
    77  }
    78  
    79  func (matcher *PlanMatcher) FailureMessage(actual interface{}) string {
    80  	return matcher.failedMatcher.FailureMessage(matcher.failedValue)
    81  }
    82  
    83  func (matcher *PlanMatcher) NegatedFailureMessage(actual interface{}) string {
    84  	return matcher.failedMatcher.NegatedFailureMessage(matcher.failedValue)
    85  }
    86  
    87  func stripIDs(plan atc.Plan) (atc.Plan, []string) {
    88  	ids := []string{}
    89  
    90  	// Ignore errors, since our walker doesn't return an error.
    91  	plan.Each(func(plan *atc.Plan) {
    92  		ids = append(ids, string(plan.ID))
    93  
    94  		plan.ID = "<stripped>"
    95  
    96  		if plan.Get != nil {
    97  			if plan.Get.VersionFrom != nil {
    98  				planID := atc.PlanID("<stripped>")
    99  				plan.Get.VersionFrom = &planID
   100  			}
   101  		}
   102  	})
   103  
   104  	return plan, ids
   105  }