LCOV - code coverage report
Current view: top level - pebble/internal/itertest - dsl.go (source / functions) Hit Total Coverage
Test: 2024-01-22 08:16Z 5b092519 - tests + meta.lcov Lines: 86 105 81.9 %
Date: 2024-01-22 08:17:12 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 :                         ik := base.ParseInternalKey(s.ConsumeString())
      54           1 :                         val := []byte(s.ConsumeString())
      55           1 :                         s.Consume(token.RPAREN)
      56           1 :                         return ReturnKV(&ik, val)
      57           1 :                 })
      58           1 :         probeParser.DefineFunc("Log",
      59           1 :                 func(p *dsl.Parser[Probe], s *dsl.Scanner) (ret Probe) {
      60           1 :                         ret = loggingProbe{prefix: s.ConsumeString()}
      61           1 :                         s.Consume(token.RPAREN)
      62           1 :                         return ret
      63           1 :                 })
      64           1 :         return probeParser
      65             : }
      66             : 
      67             : // ErrInjected is an error artificially injected for testing.
      68             : var ErrInjected = Error("ErrInjected", errorfs.ErrInjected)
      69             : 
      70             : // Error returns a Probe that returns the provided error. The name is Name
      71             : // returned by String().
      72           1 : func Error(name string, err error) *ErrorProbe {
      73           1 :         return &ErrorProbe{name: name, err: err}
      74           1 : }
      75             : 
      76             : // ErrorProbe is a Probe that injects an error.
      77             : type ErrorProbe struct {
      78             :         name string
      79             :         err  error
      80             : }
      81             : 
      82             : // String implements fmt.Stringer.
      83           0 : func (p *ErrorProbe) String() string {
      84           0 :         return p.name
      85           0 : }
      86             : 
      87             : // Error implements error, so that injected error values may be used as probes
      88             : // that inject themselves.
      89           0 : func (p *ErrorProbe) Error() error {
      90           0 :         return p.err
      91           0 : }
      92             : 
      93             : // Probe implements the Probe interface, replacing the iterator return value
      94             : // with an error.
      95           1 : func (p *ErrorProbe) Probe(pctx *ProbeContext) {
      96           1 :         pctx.Op.Return.Err = p.err
      97           1 :         pctx.Op.Return.Key = nil
      98           1 :         pctx.Op.Return.Value = base.LazyValue{}
      99           1 : }
     100             : 
     101             : // If a conditional Probe. If its predicate evaluates to true, it probes using
     102             : // its Then probe. If its predicate evalutes to false, it probes using its Else
     103             : // probe.
     104           1 : func If(pred Predicate, thenProbe, elseProbe Probe) Probe {
     105           1 :         return ifProbe{pred, thenProbe, elseProbe}
     106           1 : }
     107             : 
     108             : type ifProbe struct {
     109             :         Predicate Predicate
     110             :         Then      Probe
     111             :         Else      Probe
     112             : }
     113             : 
     114             : // String implements fmt.Stringer.
     115           0 : func (p ifProbe) String() string { return fmt.Sprintf("(If %s %s %s)", p.Predicate, p.Then, p.Else) }
     116             : 
     117             : // Probe implements Probe.
     118           1 : func (p ifProbe) Probe(pctx *ProbeContext) {
     119           1 :         if p.Predicate.Evaluate(pctx) {
     120           1 :                 p.Then.Probe(pctx)
     121           1 :         } else {
     122           1 :                 p.Else.Probe(pctx)
     123           1 :         }
     124             : }
     125             : 
     126             : type loggingProbe struct {
     127             :         prefix string
     128             : }
     129             : 
     130           0 : func (lp loggingProbe) String() string { return fmt.Sprintf("(Log %q)", lp.prefix) }
     131           1 : func (lp loggingProbe) Probe(pctx *ProbeContext) {
     132           1 :         opStr := strings.TrimPrefix(pctx.Kind.String(), "Op")
     133           1 :         fmt.Fprintf(pctx.Log, "%s%s(", lp.prefix, opStr)
     134           1 :         if pctx.SeekKey != nil {
     135           1 :                 fmt.Fprintf(pctx.Log, "%q", pctx.SeekKey)
     136           1 :         }
     137           1 :         fmt.Fprint(pctx.Log, ") = ")
     138           1 :         if pctx.Return.Key == nil {
     139           1 :                 fmt.Fprint(pctx.Log, "nil")
     140           1 :                 if pctx.Return.Err != nil {
     141           1 :                         fmt.Fprintf(pctx.Log, " <err=%q>", pctx.Return.Err)
     142           1 :                 }
     143           1 :         } else {
     144           1 :                 v, _, err := pctx.Return.Value.Value(nil)
     145           1 :                 if err != nil {
     146           0 :                         panic(err)
     147             :                 }
     148           1 :                 fmt.Fprintf(pctx.Log, "(%s,%q)", pctx.Return.Key, v)
     149             :         }
     150           1 :         fmt.Fprintln(pctx.Log)
     151             : }
     152             : 
     153             : // UserKey implements a predicate that evaluates to true if the returned
     154             : // InternalKey holds a specific user key.
     155             : type UserKey []byte
     156             : 
     157             : // String implements fmt.Stringer.
     158           0 : func (p UserKey) String() string { return fmt.Sprintf("(UserKey %q)", string(p)) }
     159             : 
     160             : // Evaluate implements Predicate.
     161           0 : func (p UserKey) Evaluate(pctx *ProbeContext) bool {
     162           0 :         return pctx.Op.Return.Key != nil && pctx.Comparer.Equal(pctx.Op.Return.Key.UserKey, p)
     163           0 : }
     164             : 
     165             : // ReturnKV returns a Probe that modifies an operation's return value to the
     166             : // provided KV pair.
     167           1 : func ReturnKV(k *base.InternalKey, v []byte) Probe {
     168           1 :         return &returnKV{k, v}
     169           1 : }
     170             : 
     171             : type returnKV struct {
     172             :         *base.InternalKey
     173             :         Value []byte
     174             : }
     175             : 
     176             : // Probe implements Probe.
     177           1 : func (kv *returnKV) Probe(pctx *ProbeContext) {
     178           1 :         pctx.Op.Return.Key = kv.InternalKey
     179           1 :         pctx.Op.Return.Value = base.MakeInPlaceValue(kv.Value)
     180           1 : }
     181             : 
     182             : // Noop returns a Probe that does nothing.
     183           1 : func Noop() Probe { return noop{} }
     184             : 
     185             : type noop struct{}
     186             : 
     187           0 : func (noop) String() string           { return "noop" }
     188           1 : func (noop) Probe(pctx *ProbeContext) {}
     189             : 
     190             : // Nil returns a Probe that always returns nil.
     191           1 : func Nil() Probe { return returnNil{} }
     192             : 
     193             : type returnNil struct{}
     194             : 
     195           0 : func (returnNil) String() string { return "Nil" }
     196           1 : func (returnNil) Probe(pctx *ProbeContext) {
     197           1 :         pctx.Op.Return.Key = nil
     198           1 :         pctx.Op.Return.Value = base.LazyValue{}
     199           1 : }

Generated by: LCOV version 1.14