From 60dcafe04dbb86267a48b8f18a9a2d63a5ae67dc Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sat, 10 Apr 2021 13:42:17 +0100 Subject: [PATCH] test makefiles: add --seed flag and make data generated repeatable #5214 --- cmd/test/makefiles/makefiles.go | 22 +++++++++++++++------- lib/random/random.go | 14 +++++++++++--- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cmd/test/makefiles/makefiles.go b/cmd/test/makefiles/makefiles.go index 07db517f2..abbab739d 100644 --- a/cmd/test/makefiles/makefiles.go +++ b/cmd/test/makefiles/makefiles.go @@ -3,12 +3,12 @@ package makefiles import ( - cryptrand "crypto/rand" "io" "log" "math/rand" "os" "path/filepath" + "time" "github.com/rclone/rclone/cmd" "github.com/rclone/rclone/cmd/test" @@ -27,8 +27,10 @@ var ( maxFileSize = fs.SizeSuffix(100) minFileNameLength = 4 maxFileNameLength = 12 + seed = int64(1) // Globals + randSource *rand.Rand directoriesToCreate int totalDirectories int fileNames = map[string]struct{}{} // keep a note of which file name we've used already @@ -44,6 +46,7 @@ func init() { flags.FVarP(cmdFlags, &maxFileSize, "max-file-size", "", "Maximum size of files to create") flags.IntVarP(cmdFlags, &minFileNameLength, "min-name-length", "", minFileNameLength, "Minimum size of file names") flags.IntVarP(cmdFlags, &maxFileNameLength, "max-name-length", "", maxFileNameLength, "Maximum size of file names") + flags.Int64VarP(cmdFlags, &seed, "seed", "", seed, "Seed for the random number generator (0 for random)") } var commandDefinition = &cobra.Command{ @@ -51,6 +54,11 @@ var commandDefinition = &cobra.Command{ Short: `Make a random file hierarchy in `, Run: func(command *cobra.Command, args []string) { cmd.CheckArgs(1, 1, command, args) + if seed == 0 { + seed = time.Now().UnixNano() + log.Printf("Using random seed = %d", seed) + } + randSource = rand.New(rand.NewSource(seed)) outputDirectory := args[0] directoriesToCreate = numberOfFiles / averageFilesPerDirectory averageSize := (minFileSize + maxFileSize) / 2 @@ -61,7 +69,7 @@ var commandDefinition = &cobra.Command{ } dirs := root.list("", []string{}) for i := 0; i < numberOfFiles; i++ { - dir := dirs[rand.Intn(len(dirs))] + dir := dirs[randSource.Intn(len(dirs))] writeFile(dir, fileName()) } log.Printf("Done.") @@ -71,8 +79,8 @@ var commandDefinition = &cobra.Command{ // fileName creates a unique random file or directory name func fileName() (name string) { for { - length := rand.Intn(maxFileNameLength-minFileNameLength) + minFileNameLength - name = random.String(length) + length := randSource.Intn(maxFileNameLength-minFileNameLength) + minFileNameLength + name = random.StringFn(length, randSource.Intn) if _, found := fileNames[name]; !found { break } @@ -99,7 +107,7 @@ func (d *dir) createDirectories() { } d.children = append(d.children, newDir) totalDirectories++ - switch rand.Intn(4) { + switch randSource.Intn(4) { case 0: if d.depth < maxDepth { newDir.createDirectories() @@ -132,8 +140,8 @@ func writeFile(dir, name string) { if err != nil { log.Fatalf("Failed to open file %q: %v", path, err) } - size := rand.Int63n(int64(maxFileSize-minFileSize)) + int64(minFileSize) - _, err = io.CopyN(fd, cryptrand.Reader, size) + size := randSource.Int63n(int64(maxFileSize-minFileSize)) + int64(minFileSize) + _, err = io.CopyN(fd, randSource, size) if err != nil { log.Fatalf("Failed to write %v bytes to file %q: %v", size, path, err) } diff --git a/lib/random/random.go b/lib/random/random.go index 57a858beb..30198bdd4 100644 --- a/lib/random/random.go +++ b/lib/random/random.go @@ -10,10 +10,11 @@ import ( "github.com/pkg/errors" ) -// String create a random string for test purposes. +// StringFn create a random string for test purposes using the random +// number generator function passed in. // // Do not use these for passwords. -func String(n int) string { +func StringFn(n int, randIntn func(n int) int) string { const ( vowel = "aeiou" consonant = "bcdfghjklmnpqrstvwxyz" @@ -25,11 +26,18 @@ func String(n int) string { for i := range out { source := pattern[p] p = (p + 1) % len(pattern) - out[i] = source[mathrand.Intn(len(source))] + out[i] = source[randIntn(len(source))] } return string(out) } +// String create a random string for test purposes. +// +// Do not use these for passwords. +func String(n int) string { + return StringFn(n, mathrand.Intn) +} + // Password creates a crypto strong password which is just about // memorable. The password is composed of printable ASCII characters // from the base64 alphabet.