github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fstest/test_all/test_all.go (about) 1 // Run tests for all the remotes. Run this with package names which 2 // need integration testing. 3 // 4 // See the `test` target in the Makefile. 5 package main 6 7 /* FIXME 8 9 Make TesTrun have a []string of flags to try - that then makes it generic 10 11 */ 12 13 import ( 14 "flag" 15 "log" 16 "math/rand" 17 "os" 18 "path" 19 "regexp" 20 "strings" 21 "time" 22 23 _ "github.com/rclone/rclone/backend/all" // import all fs 24 "github.com/rclone/rclone/fs/config/configfile" 25 "github.com/rclone/rclone/lib/pacer" 26 ) 27 28 var ( 29 // Flags 30 maxTries = flag.Int("maxtries", 5, "Number of times to try each test") 31 maxN = flag.Int("n", 20, "Maximum number of tests to run at once") 32 testRemotes = flag.String("remotes", "", "Comma separated list of remotes to test, e.g. 'TestSwift:,TestS3'") 33 testBackends = flag.String("backends", "", "Comma separated list of backends to test, e.g. 's3,googlecloudstorage") 34 testTests = flag.String("tests", "", "Comma separated list of tests to test, e.g. 'fs/sync,fs/operations'") 35 clean = flag.Bool("clean", false, "Instead of testing, clean all left over test directories") 36 runOnly = flag.String("run", "", "Run only those tests matching the regexp supplied") 37 timeout = flag.Duration("timeout", 60*time.Minute, "Maximum time to run each test for before giving up") 38 race = flag.Bool("race", false, "If set run the tests under the race detector") 39 configFile = flag.String("config", "fstest/test_all/config.yaml", "Path to config file") 40 outputDir = flag.String("output", path.Join(os.TempDir(), "rclone-integration-tests"), "Place to store results") 41 emailReport = flag.String("email", "", "Set to email the report to the address supplied") 42 dryRun = flag.Bool("dry-run", false, "Print commands which would be executed only") 43 urlBase = flag.String("url-base", "https://pub.rclone.org/integration-tests/", "Base for the online version") 44 uploadPath = flag.String("upload", "", "Set this to an rclone path to upload the results here") 45 verbose = flag.Bool("verbose", false, "Set to enable verbose logging in the tests") 46 listRetries = flag.Int("list-retries", -1, "Number or times to retry listing - set to override the default") 47 ) 48 49 // if matches then is definitely OK in the shell 50 var shellOK = regexp.MustCompile("^[A-Za-z0-9./_:-]+$") 51 52 // converts an argv style input into a shell command 53 func toShell(args []string) (result string) { 54 for _, arg := range args { 55 if result != "" { 56 result += " " 57 } 58 if shellOK.MatchString(arg) { 59 result += arg 60 } else { 61 result += "'" + arg + "'" 62 } 63 } 64 return result 65 } 66 67 func main() { 68 flag.Parse() 69 conf, err := NewConfig(*configFile) 70 if err != nil { 71 log.Println("test_all should be run from the root of the rclone source code") 72 log.Fatal(err) 73 } 74 configfile.Install() 75 76 // Seed the random number generator 77 randInstance := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 78 79 // Filter selection 80 if *testRemotes != "" { 81 conf.filterBackendsByRemotes(strings.Split(*testRemotes, ",")) 82 } 83 if *testBackends != "" { 84 conf.filterBackendsByBackends(strings.Split(*testBackends, ",")) 85 } 86 if *testTests != "" { 87 conf.filterTests(strings.Split(*testTests, ",")) 88 } 89 90 // Just clean the directories if required 91 if *clean { 92 err := cleanRemotes(conf) 93 if err != nil { 94 log.Fatalf("Failed to clean: %v", err) 95 } 96 return 97 } 98 99 var names []string 100 for _, remote := range conf.Backends { 101 names = append(names, remote.Remote) 102 } 103 log.Printf("Testing remotes: %s", strings.Join(names, ", ")) 104 105 // Runs we will do for this test in random order 106 runs := conf.MakeRuns() 107 randInstance.Shuffle(len(runs), runs.Swap) 108 109 // Create Report 110 report := NewReport() 111 112 // Make the test binaries, one per Path found in the tests 113 done := map[string]struct{}{} 114 for _, run := range runs { 115 if _, found := done[run.Path]; !found { 116 done[run.Path] = struct{}{} 117 if !run.NoBinary { 118 run.MakeTestBinary() 119 defer run.RemoveTestBinary() 120 } 121 } 122 } 123 124 // workaround for cache backend as we run simultaneous tests 125 _ = os.Setenv("RCLONE_CACHE_DB_WAIT_TIME", "30m") 126 127 // start the tests 128 results := make(chan *Run, len(runs)) 129 awaiting := 0 130 tokens := pacer.NewTokenDispenser(*maxN) 131 for _, run := range runs { 132 tokens.Get() 133 go func(run *Run) { 134 defer tokens.Put() 135 run.Run(report.LogDir, results) 136 }(run) 137 awaiting++ 138 } 139 140 // Wait for the tests to finish 141 for ; awaiting > 0; awaiting-- { 142 t := <-results 143 report.RecordResult(t) 144 } 145 146 // Log and exit 147 report.End() 148 report.LogSummary() 149 report.LogJSON() 150 report.LogHTML() 151 report.EmailHTML() 152 report.Upload() 153 if !report.AllPassed() { 154 os.Exit(1) 155 } 156 }