github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fstest/test_all/test_all.go (about)

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