LCOV - code coverage report
Current view: top level - pebble/internal/itertest - dsl.go (source / functions) Hit Total Coverage
Test: 2024-06-07 08:15Z 47da75f0 - tests + meta.lcov Lines: 82 101 81.2 %
Date: 2024-06-07 08:16:47 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package itertest
       6             : 
       7             : import (
       8             :         "fmt"
       9             :         "go/token"
      10             :         "strings"
      11             : 
      12             :         "github.com/cockroachdb/pebble/internal/base"
      13             :         "github.com/cockroachdb/pebble/internal/dsl"
      14             :         "github.com/cockroachdb/pebble/vfs/errorfs"
      15             : )
      16             : 
      17             : // Predicate encodes conditional logic that yields a boolean.
      18             : type Predicate = dsl.Predicate[*ProbeContext]
      19             : 
      20             : // NewParser constructs a Probe parser.
      21           1 : func NewParser() *dsl.Parser[Probe] {
      22           1 :         predicateParser := dsl.NewPredicateParser[*ProbeContext]()
      23           1 :         for i, name := range opNames {
      24           1 :                 opKind := OpKind(i)
      25           1 :                 predicateParser.DefineConstant(name, func() dsl.Predicate[*ProbeContext] {
      26           1 :                         // An OpKind implements dsl.Predicate[*ProbeContext].
      27           1 :                         return opKind
      28           1 :                 })
      29             :         }
      30           1 :         predicateParser.DefineFunc("UserKey",
      31           1 :                 func(p *dsl.Parser[Predicate], s *dsl.Scanner) dsl.Predicate[*ProbeContext] {
      32           0 :                         userKey := s.ConsumeString()
      33           0 :                         s.Consume(token.RPAREN)
      34           0 :                         return UserKey(userKey)
      35           0 :                 })
      36             : 
      37           1 :         probeParser := dsl.NewParser[Probe]()
      38           1 :         probeParser.DefineConstant("ErrInjected", func() Probe { return ErrInjected })
      39           1 :         probeParser.DefineConstant("noop", Noop)
      40           1 :         probeParser.DefineConstant("Nil", Nil)
      41           1 :         probeParser.DefineFunc("If",
      42           1 :                 func(p *dsl.Parser[Probe], s *dsl.Scanner) Probe {
      43           1 :                         pred := If(
      44           1 :                                 predicateParser.ParseFromPos(s, s.Scan()),
      45           1 :                                 probeParser.ParseFromPos(s, s.Scan()),
      46           1 :                                 probeParser.ParseFromPos(s, s.Scan()),
      47           1 :                         )
      48           1 :                         s.Consume(token.RPAREN)
      49           1 :                         return pred
      50           1 :                 })
      51           1 :         probeParser.DefineFunc("ReturnKV",
      52           1 :                 func(p *dsl.Parser[Probe], s *dsl.Scanner) Probe {
      53           1 :                         kv := base.MakeInternalKV(base.ParseInternalKey(s.ConsumeString()), []byte(s.ConsumeString()))
      54           1 :                         s.Consume(token.RPAREN)
      55           1 :                         return ReturnKV(&kv)
      56           1 :                 })
      57           1 :         probeParser.DefineFunc("Log",
      58           1 :                 func(p *dsl.Parser[Probe], s *dsl.Scanner) (ret Probe) {
      59           1 :                         ret = loggingProbe{prefix: s.ConsumeString()}
      60           1 :                         s.Consume(token.RPAREN)
      61           1 :                         return ret
      62           1 :                 })
      63           1 :         return probeParser
      64             : }
      65             : 
      66             : // ErrInjected is an error artificially injected for testing.
      67             : var ErrInjected = Error("ErrInjected", errorfs.ErrInjected)
      68             : 
      69             : // Error returns a Probe that returns the provided error. The name is Name
      70             : // returned by String().
      71           1 : func Error(name string, err error) *ErrorProbe {
      72           1 :         return &ErrorProbe{name: name, err: err}
      73           1 : }
      74             : 
      75             : // ErrorProbe is a Probe that injects an error.
      76             : type ErrorProbe struct {
      77             :         name string
      78             :         err  error
      79             : }
      80             : 
      81             : // String implements fmt.Stringer.
      82           0 : func (p *ErrorProbe) String() string {
      83           0 :         return p.name
      84           0 : }
      85             : 
      86             : // Error implements error, so that injected error values may be used as probes
      87             : // that inject themselves.
      88           0 : func (p *ErrorProbe) Error() error {
      89           0 :         return p.err
      90           0 : }
      91             : 
      92             : // Probe implements the Probe interface, replacing the iterator return value
      93             : // with an error.
      94           1 : func (p *ErrorProbe) Probe(pctx *ProbeContext) {
      95           1 :         pctx.Op.Return.Err = p.err
      96           1 :         pctx.Op.Return.KV = nil
      97           1 : }
      98             : 
      99             : // If a conditional Probe. If its predicate evaluates to true, it probes using
     100             : // its Then probe. If its predicate evalutes to false, it probes using its Else
     101             : // probe.
     102           1 : func If(pred Predicate, thenProbe, elseProbe Probe) Probe {
     103           1 :         return ifProbe{pred, thenProbe, elseProbe}
     104           1 : }
     105             : 
     106             : type ifProbe struct {
     107             :         Predicate Predicate
     108             :         Then      Probe
     109             :         Else      Probe
     110             : }
     111             : 
     112             : // String implements fmt.Stringer.
     113           0 : func (p ifProbe) String() string { return fmt.Sprintf("(If %s %s %s)", p.Predicate, p.Then, p.Else) }
     114             : 
     115             : // Probe implements Probe.
     116           1 : func (p ifProbe) Probe(pctx *ProbeContext) {
     117           1 :         if p.Predicate.Evaluate(pctx) {
     118           1 :                 p.Then.Probe(pctx)
     119           1 :         } else {
     120           1 :                 p.Else.Probe(pctx)
     121           1 :         }
     122             : }
     123             : 
     124             : type loggingProbe struct {
     125             :         prefix string
     126             : }
     127             : 
     128           0 : func (lp loggingProbe) String() string { return fmt.Sprintf("(Log %q)", lp.prefix) }
     129           1 : func (lp loggingProbe) Probe(pctx *ProbeContext) {
     130           1 :         opStr := strings.TrimPrefix(pctx.Kind.String(), "Op")
     131           1 :         fmt.Fprintf(pctx.Log, "%s%s(", lp.prefix, opStr)
     132           1 :         if pctx.SeekKey != nil {
     133           1 :                 fmt.Fprintf(pctx.Log, "%q", pctx.SeekKey)
     134           1 :         }
     135           1 :         fmt.Fprint(pctx.Log, ") = ")
     136           1 :         if pctx.Return.KV == nil {
     137           1 :                 fmt.Fprint(pctx.Log, "nil")
     138           1 :                 if pctx.Return.Err != nil {
     139           1 :                         fmt.Fprintf(pctx.Log, " <err=%q>", pctx.Return.Err)
     140           1 :                 }
     141           1 :         } else {
     142           1 :                 v, _, err := pctx.Return.KV.Value(nil)
     143           1 :                 if err != nil {
     144           0 :                         panic(err)
     145             :                 }
     146           1 :                 fmt.Fprintf(pctx.Log, "(%s,%q)", pctx.Return.KV.K, v)
     147             :         }
     148           1 :         fmt.Fprintln(pctx.Log)
     149             : }
     150             : 
     151             : // UserKey implements a predicate that evaluates to true if the returned
     152             : // InternalKey holds a specific user key.
     153             : type UserKey []byte
     154             : 
     155             : // String implements fmt.Stringer.
     156           0 : func (p UserKey) String() string { return fmt.Sprintf("(UserKey %q)", string(p)) }
     157             : 
     158             : // Evaluate implements Predicate.
     159           0 : func (p UserKey) Evaluate(pctx *ProbeContext) bool {
     160           0 :         return pctx.Op.Return.KV != nil && pctx.Comparer.Equal(pctx.Op.Return.KV.K.UserKey, p)
     161           0 : }
     162             : 
     163             : // ReturnKV returns a Probe that modifies an operation's return value to the
     164             : // provided KV pair.
     165           1 : func ReturnKV(kv *base.InternalKV) Probe {
     166           1 :         return &returnKV{kv}
     167           1 : }
     168             : 
     169             : type returnKV struct {
     170             :         *base.InternalKV
     171             : }
     172             : 
     173             : // Probe implements Probe.
     174           1 : func (kv *returnKV) Probe(pctx *ProbeContext) {
     175           1 :         pctx.Op.Return.KV = kv.InternalKV
     176           1 : }
     177             : 
     178             : // Noop returns a Probe that does nothing.
     179           1 : func Noop() Probe { return noop{} }
     180             : 
     181             : type noop struct{}
     182             : 
     183           0 : func (noop) String() string           { return "noop" }
     184           1 : func (noop) Probe(pctx *ProbeContext) {}
     185             : 
     186             : // Nil returns a Probe that always returns nil.
     187           1 : func Nil() Probe { return returnNil{} }
     188             : 
     189             : type returnNil struct{}
     190             : 
     191           0 : func (returnNil) String() string { return "Nil" }
     192           1 : func (returnNil) Probe(pctx *ProbeContext) {
     193           1 :         pctx.Op.Return.KV = nil
     194           1 : }

Generated by: LCOV version 1.14