@@ -8,11 +8,11 @@ package tests
88import (
99 "context"
1010 "fmt"
11- "hash"
1211 "hash/fnv"
1312 "math/rand"
1413 "os"
1514 "path/filepath"
15+ "regexp"
1616 "strings"
1717 "testing"
1818 "time"
@@ -35,8 +35,10 @@ import (
3535 "github.com/cockroachdb/cockroach/pkg/util/humanizeutil"
3636 "github.com/cockroachdb/cockroach/pkg/util/leaktest"
3737 "github.com/cockroachdb/cockroach/pkg/util/log"
38+ "github.com/cockroachdb/cockroach/pkg/util/tracing/tracingpb"
3839 "github.com/cockroachdb/datadriven"
3940 "github.com/cockroachdb/logtags"
41+ "github.com/stretchr/testify/assert"
4042 "github.com/stretchr/testify/require"
4143)
4244
@@ -165,6 +167,12 @@ var runAsimTests = envutil.EnvOrDefaultBool("COCKROACH_RUN_ASIM_TESTS", false)
165167// random number generator that creates the seed used to generate each
166168// simulation sample. The default values are: duration=30m (30 minutes)
167169// samples=1 seed=random.
170+ //
171+ // To run all tests and rewrite the testdata files as well as generate the
172+ // artifacts in `testdata/generated`, you can use:
173+ /*
174+ ./dev test pkg/kv/kvserver/asim/tests --ignore-cache --rewrite -v -f TestDataDriven -- --test_env COCKROACH_RUN_ASIM_TESTS=true --test_env COCKROACH_ALWAYS_KEEP_TEST_LOGS=true
175+ */
168176func TestDataDriven (t * testing.T ) {
169177 skip .UnderDuressWithIssue (t , 149875 )
170178 leakTestAfter := leaktest .AfterTest (t )
@@ -531,7 +539,34 @@ func TestDataDriven(t *testing.T) {
531539 require .NotNil (t , set , "unknown mode value: %s" , mv )
532540 set (& eventGen )
533541
542+ // TODO(tbg): need to decide whether multiple evals in a single file
543+ // is a feature or an anti-pattern. If it's a feature, we should let
544+ // the `name` part below be adjustable (but not the plotDir) via a
545+ // parameter to the `eval` command.
546+ testName := name + "_" + mv
547+
534548 for sample := 0 ; sample < samples ; sample ++ {
549+ recIdx := map [int64 ]int {}
550+ settingsGen .Settings .OnRecording = func (storeID int64 , rec tracingpb.Recording ) {
551+ if ! rewrite || len (rec [0 ].Logs ) == 0 {
552+ return
553+ }
554+ traceDir := filepath .Join (plotDir , "traces" , fmt .Sprintf ("s%d" , storeID ))
555+ if recIdx [storeID ] == 0 {
556+ require .NoError (t , os .MkdirAll (traceDir , 0755 ))
557+ }
558+ re := regexp .MustCompile (`[^a-zA-Z0-9]+` )
559+ outName := fmt .Sprintf ("%s_%s_s%d" , mv , re .ReplaceAllString (rec [0 ].Operation , "_" ), storeID )
560+ if sample > 0 {
561+ outName += fmt .Sprintf ("_sample%d" , sample + 1 )
562+ }
563+ outName += "_" + fmt .Sprintf ("%03d.txt" , recIdx [storeID ])
564+ assert .NoError (t , os .WriteFile (
565+ filepath .Join (traceDir , outName ),
566+ []byte (rec .String ()), 0644 ))
567+ recIdx [storeID ] += 1
568+ }
569+
535570 assertionFailures := []string {}
536571 var tmpStrB * strings.Builder = nil
537572 if stateStrForOnce == "" {
@@ -561,17 +596,10 @@ func TestDataDriven(t *testing.T) {
561596 // Generate artifacts. Hash artifact input data to ensure they are
562597 // up to date.
563598 hasher := fnv .New64a ()
564- // TODO(tbg): need to decide whether multiple evals in a single file
565- // is a feature or an anti-pattern. If it's a feature, we should let
566- // the `name` part below be adjustable (but not the plotDir) via a
567- // parameter to the `eval` command.
568- testName := name + "_" + mv
599+
569600 for sample , h := range run .hs {
570- generateAllPlots (t , & buf , h , testName , sample + 1 , plotDir , hasher , rewrite ,
601+ printStatsAndGenerateJSON (t , & buf , h , testName , sample + 1 , plotDir , hasher , rewrite ,
571602 settingsGen .Settings .TickInterval , metricsMap )
572- generateTopology (t , h ,
573- filepath .Join (plotDir , fmt .Sprintf ("%s_%d_topology.txt" , testName , sample + 1 )),
574- hasher , rewrite )
575603 }
576604 artifactsHash := hasher .Sum64 ()
577605
@@ -707,22 +735,6 @@ type modeHistory struct {
707735 hs []history.History
708736}
709737
710- func generateTopology (
711- t * testing.T , h history.History , topFile string , hasher hash.Hash , rewrite bool ,
712- ) {
713- // TODO(tbg): this can in principle be printed without even
714- // evaluating the test, and in particular it's independent of
715- // settings. It seems like an artifact of the implementation
716- // that we can only access the structured topology after the
717- // simulation has run.
718- top := h .S .Topology ()
719- s := top .String ()
720- _ , _ = fmt .Fprint (hasher , s )
721- if rewrite {
722- require .NoError (t , os .WriteFile (topFile , []byte (s ), 0644 ))
723- }
724- }
725-
726738// writeStateStrToFile writes the state string to the given file.
727739func writeStateStrToFile (t * testing.T , topFile string , stateStr string , rewrite bool ) {
728740 if rewrite {
0 commit comments