github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/concurrency/datadriven_util_test.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package concurrency_test
    12  
    13  import (
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock"
    19  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    20  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    21  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    22  	"github.com/cockroachdb/cockroach/pkg/util/uint128"
    23  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    24  	"github.com/cockroachdb/datadriven"
    25  )
    26  
    27  func nextUUID(counter *uint32) uuid.UUID {
    28  	*counter = *counter + 1
    29  	hi := uint64(*counter) << 32
    30  	return uuid.FromUint128(uint128.Uint128{Hi: hi})
    31  }
    32  
    33  func scanTimestamp(t *testing.T, d *datadriven.TestData) hlc.Timestamp {
    34  	return scanTimestampWithName(t, d, "ts")
    35  }
    36  
    37  func scanTimestampWithName(t *testing.T, d *datadriven.TestData, name string) hlc.Timestamp {
    38  	var ts hlc.Timestamp
    39  	var tsS string
    40  	d.ScanArgs(t, name, &tsS)
    41  	parts := strings.Split(tsS, ",")
    42  
    43  	// Find the wall time part.
    44  	tsW, err := strconv.ParseInt(parts[0], 10, 64)
    45  	if err != nil {
    46  		d.Fatalf(t, "%v", err)
    47  	}
    48  	ts.WallTime = tsW
    49  
    50  	// Find the logical part, if there is one.
    51  	var tsL int64
    52  	if len(parts) > 1 {
    53  		tsL, err = strconv.ParseInt(parts[1], 10, 32)
    54  		if err != nil {
    55  			d.Fatalf(t, "%v", err)
    56  		}
    57  	}
    58  	ts.Logical = int32(tsL)
    59  	return ts
    60  }
    61  
    62  func scanLockDurability(t *testing.T, d *datadriven.TestData) lock.Durability {
    63  	var durS string
    64  	d.ScanArgs(t, "dur", &durS)
    65  	switch durS {
    66  	case "r":
    67  		return lock.Replicated
    68  	case "u":
    69  		return lock.Unreplicated
    70  	default:
    71  		d.Fatalf(t, "unknown lock durability: %s", durS)
    72  		return 0
    73  	}
    74  }
    75  
    76  func scanSingleRequest(
    77  	t *testing.T, d *datadriven.TestData, line string, txns map[string]*roachpb.Transaction,
    78  ) roachpb.Request {
    79  	cmd, cmdArgs, err := datadriven.ParseLine(line)
    80  	if err != nil {
    81  		d.Fatalf(t, "error parsing single request: %v", err)
    82  		return nil
    83  	}
    84  
    85  	fields := make(map[string]string, len(cmdArgs))
    86  	for _, cmdArg := range cmdArgs {
    87  		if len(cmdArg.Vals) != 1 {
    88  			d.Fatalf(t, "unexpected command values: %+v", cmdArg)
    89  			return nil
    90  		}
    91  		fields[cmdArg.Key] = cmdArg.Vals[0]
    92  	}
    93  	mustGetField := func(f string) string {
    94  		v, ok := fields[f]
    95  		if !ok {
    96  			d.Fatalf(t, "missing required field: %s", f)
    97  		}
    98  		return v
    99  	}
   100  	maybeGetSeq := func() enginepb.TxnSeq {
   101  		s, ok := fields["seq"]
   102  		if !ok {
   103  			return 0
   104  		}
   105  		n, err := strconv.ParseInt(s, 10, 64)
   106  		if err != nil {
   107  			d.Fatalf(t, "could not parse seq num: %v", err)
   108  		}
   109  		return enginepb.TxnSeq(n)
   110  	}
   111  
   112  	switch cmd {
   113  	case "get":
   114  		var r roachpb.GetRequest
   115  		r.Sequence = maybeGetSeq()
   116  		r.Key = roachpb.Key(mustGetField("key"))
   117  		return &r
   118  
   119  	case "scan":
   120  		var r roachpb.ScanRequest
   121  		r.Sequence = maybeGetSeq()
   122  		r.Key = roachpb.Key(mustGetField("key"))
   123  		if v, ok := fields["endkey"]; ok {
   124  			r.EndKey = roachpb.Key(v)
   125  		}
   126  		return &r
   127  
   128  	case "put":
   129  		var r roachpb.PutRequest
   130  		r.Sequence = maybeGetSeq()
   131  		r.Key = roachpb.Key(mustGetField("key"))
   132  		r.Value.SetString(mustGetField("value"))
   133  		return &r
   134  
   135  	case "resolve-intent":
   136  		var r roachpb.ResolveIntentRequest
   137  		r.IntentTxn = txns[mustGetField("txn")].TxnMeta
   138  		r.Key = roachpb.Key(mustGetField("key"))
   139  		r.Status = parseTxnStatus(t, d, mustGetField("status"))
   140  		return &r
   141  
   142  	case "request-lease":
   143  		var r roachpb.RequestLeaseRequest
   144  		return &r
   145  
   146  	default:
   147  		d.Fatalf(t, "unknown request type: %s", cmd)
   148  		return nil
   149  	}
   150  }
   151  
   152  func scanTxnStatus(t *testing.T, d *datadriven.TestData) (roachpb.TransactionStatus, string) {
   153  	var statusStr string
   154  	d.ScanArgs(t, "status", &statusStr)
   155  	status := parseTxnStatus(t, d, statusStr)
   156  	var verb string
   157  	switch status {
   158  	case roachpb.COMMITTED:
   159  		verb = "committing"
   160  	case roachpb.ABORTED:
   161  		verb = "aborting"
   162  	case roachpb.PENDING:
   163  		verb = "increasing timestamp of"
   164  	default:
   165  		d.Fatalf(t, "unknown txn status: %s", status)
   166  	}
   167  	return status, verb
   168  }
   169  
   170  func parseTxnStatus(t *testing.T, d *datadriven.TestData, s string) roachpb.TransactionStatus {
   171  	switch s {
   172  	case "committed":
   173  		return roachpb.COMMITTED
   174  	case "aborted":
   175  		return roachpb.ABORTED
   176  	case "pending":
   177  		return roachpb.PENDING
   178  	default:
   179  		d.Fatalf(t, "unknown txn status: %s", s)
   180  		return 0
   181  	}
   182  }