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