vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/vreplication/queryhistory/verifier.go (about)

     1  package queryhistory
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  type Result struct {
     8  	Accepted    bool
     9  	Error       error
    10  	Expectation Expectation
    11  	Index       int
    12  	Matched     bool
    13  	Message     string
    14  }
    15  
    16  // Verifier verifies that an actual history of queries matches an expected
    17  // sequence of queries.
    18  type Verifier struct {
    19  	matched  []SequencedExpectation
    20  	pending  map[SequencedExpectation]bool
    21  	history  History
    22  	results  []*Result
    23  	sequence ExpectationSequence
    24  }
    25  
    26  func NewVerifier(sequence ExpectationSequence) *Verifier {
    27  	matched := make([]SequencedExpectation, 0)
    28  	pending := make(map[SequencedExpectation]bool)
    29  	sequence.Visit(func(e SequencedExpectation) VisitControl {
    30  		pending[e] = true
    31  		return VisitContinue
    32  	})
    33  
    34  	return &Verifier{
    35  		matched:  matched,
    36  		pending:  pending,
    37  		history:  make([]string, 0),
    38  		results:  make([]*Result, 0),
    39  		sequence: sequence,
    40  	}
    41  }
    42  
    43  // AcceptQuery verifies that the provided query is valid according to the
    44  // internal ExpectationSequence and the internal History of preceeding queries.
    45  // Returns a *Result indicating whether the query was accepted and, if not,
    46  // diagnostic details indicating why not.
    47  func (v *Verifier) AcceptQuery(query string) *Result {
    48  	history := append(v.history, query)
    49  	index := len(history) - 1
    50  	result := &Result{
    51  		Accepted:    false,
    52  		Error:       nil,
    53  		Expectation: nil,
    54  		Index:       index,
    55  		Matched:     false,
    56  		Message:     "query did not match any expectations",
    57  	}
    58  
    59  	// Evaluate query against pending expectations.
    60  	for e, p := range v.pending {
    61  		// Continue to next expectation if no longer pending.
    62  		if !p {
    63  			continue
    64  		}
    65  
    66  		if v.checkQueryAgainstExpectation(query, e, result) {
    67  			// Accept query into history.
    68  			v.history = history
    69  			v.matched = append(v.matched, e)
    70  			v.pending[e] = false
    71  			v.results = append(v.results, result)
    72  			break
    73  		}
    74  	}
    75  
    76  	return result
    77  }
    78  
    79  // History returns the internal History of accepted queries.
    80  func (v *Verifier) History() History {
    81  	return v.history
    82  }
    83  
    84  // Pending returns a list of Expectations that have not yet fully matched an
    85  // accepted query.
    86  func (v *Verifier) Pending() []Expectation {
    87  	pending := make([]Expectation, 0)
    88  	for e, p := range v.pending {
    89  		if p {
    90  			pending = append(pending, e)
    91  		}
    92  	}
    93  	return pending
    94  }
    95  
    96  func (v *Verifier) checkQueryAgainstExpectation(query string, expectation SequencedExpectation, result *Result) bool {
    97  	// Check if query matches expectation query pattern.
    98  	ok, err := expectation.MatchQuery(query)
    99  	if !ok {
   100  		if err != nil {
   101  			result.Expectation = expectation
   102  			result.Error = err
   103  			result.Message = "got an error while matching query to expectation"
   104  			return false
   105  		}
   106  		// Query did not match, continue to next expectation.
   107  		return false
   108  	}
   109  
   110  	// Query matched expectation query pattern.
   111  	result.Message = "matched an expected query"
   112  	result.Expectation = expectation
   113  
   114  	// See if it matches sequence expectations.
   115  	if expectation.ImmediatelyAfter() != nil {
   116  		if len(v.matched) == 0 {
   117  			result.Message = fmt.Sprintf(
   118  				"%q expected immediately after %q, but it is first",
   119  				query, expectation.ImmediatelyAfter().Query(),
   120  			)
   121  			return false
   122  		}
   123  		if v.pending[expectation.ImmediatelyAfter()] {
   124  			result.Message = fmt.Sprintf(
   125  				"expected immediately after %q which is not yet matched",
   126  				expectation.ImmediatelyAfter().Query(),
   127  			)
   128  			return false
   129  		}
   130  	}
   131  	for _, ea := range expectation.EventuallyAfter().Slice() {
   132  		if v.pending[ea] {
   133  			result.Message = fmt.Sprintf(
   134  				"expect eventually after %q which is not yet matched",
   135  				ea.Query(),
   136  			)
   137  			return false
   138  		}
   139  	}
   140  	if expectation.ImmediatelyBefore() != nil {
   141  		if !v.pending[expectation.ImmediatelyBefore()] {
   142  			result.Message = fmt.Sprintf(
   143  				"expected immediately before %q which is already matched",
   144  				expectation.ImmediatelyBefore().Query(),
   145  			)
   146  			return false
   147  		}
   148  	}
   149  	for _, ea := range expectation.EventuallyBefore().Slice() {
   150  		if !v.pending[ea] {
   151  			result.Message = fmt.Sprintf(
   152  				"expect eventually before %q which is already matched",
   153  				ea.Query(),
   154  			)
   155  			return false
   156  		}
   157  	}
   158  
   159  	// Query passed expectation.
   160  	result.Accepted = true
   161  	result.Matched = true
   162  	result.Message = "matched expectated query and expected order"
   163  
   164  	return true
   165  }