github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fstest/test_all/config.go (about)

     1  // Config handling
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"log"
     8  	"os"
     9  	"path"
    10  
    11  	"github.com/rclone/rclone/fs"
    12  	yaml "gopkg.in/yaml.v2"
    13  )
    14  
    15  // Test describes an integration test to run with `go test`
    16  type Test struct {
    17  	Path       string // path to the source directory
    18  	FastList   bool   // if it is possible to add -fast-list to tests
    19  	Short      bool   // if it is possible to run the test with -short
    20  	AddBackend bool   // set if Path needs the current backend appending
    21  	NoRetries  bool   // set if no retries should be performed
    22  	NoBinary   bool   // set to not build a binary in advance
    23  	LocalOnly  bool   // if set only run with the local backend
    24  }
    25  
    26  // Backend describes a backend test
    27  //
    28  // FIXME make bucket-based remotes set sub-dir automatically???
    29  type Backend struct {
    30  	Backend     string   // name of the backend directory
    31  	Remote      string   // name of the test remote
    32  	FastList    bool     // set to test with -fast-list
    33  	Short       bool     // set to test with -short
    34  	OneOnly     bool     // set to run only one backend test at once
    35  	MaxFile     string   // file size limit
    36  	CleanUp     bool     // when running clean, run cleanup first
    37  	Ignore      []string // test names to ignore the failure of
    38  	Tests       []string // paths of tests to run, blank for all
    39  	ListRetries int      // -list-retries if > 0
    40  	ExtraTime   float64  // factor to multiply the timeout by
    41  }
    42  
    43  // includeTest returns true if this backend should be included in this
    44  // test
    45  func (b *Backend) includeTest(t *Test) bool {
    46  	if len(b.Tests) == 0 {
    47  		return true
    48  	}
    49  	for _, testPath := range b.Tests {
    50  		if testPath == t.Path {
    51  			return true
    52  		}
    53  	}
    54  	return false
    55  }
    56  
    57  // MakeRuns creates Run objects the Backend and Test
    58  //
    59  // There can be several created, one for each combination of optional
    60  // flags (e.g. FastList)
    61  func (b *Backend) MakeRuns(t *Test) (runs []*Run) {
    62  	if !b.includeTest(t) {
    63  		return runs
    64  	}
    65  	maxSize := fs.SizeSuffix(0)
    66  	if b.MaxFile != "" {
    67  		if err := maxSize.Set(b.MaxFile); err != nil {
    68  			log.Printf("Invalid maxfile value %q: %v", b.MaxFile, err)
    69  		}
    70  	}
    71  	fastlists := []bool{false}
    72  	if b.FastList && t.FastList {
    73  		fastlists = append(fastlists, true)
    74  	}
    75  	ignore := make(map[string]struct{}, len(b.Ignore))
    76  	for _, item := range b.Ignore {
    77  		ignore[item] = struct{}{}
    78  	}
    79  	for _, fastlist := range fastlists {
    80  		if t.LocalOnly && b.Backend != "local" {
    81  			continue
    82  		}
    83  		run := &Run{
    84  			Remote:      b.Remote,
    85  			Backend:     b.Backend,
    86  			Path:        t.Path,
    87  			FastList:    fastlist,
    88  			Short:       (b.Short && t.Short),
    89  			NoRetries:   t.NoRetries,
    90  			OneOnly:     b.OneOnly,
    91  			NoBinary:    t.NoBinary,
    92  			SizeLimit:   int64(maxSize),
    93  			Ignore:      ignore,
    94  			ListRetries: b.ListRetries,
    95  			ExtraTime:   b.ExtraTime,
    96  		}
    97  		if t.AddBackend {
    98  			run.Path = path.Join(run.Path, b.Backend)
    99  		}
   100  		runs = append(runs, run)
   101  	}
   102  	return runs
   103  }
   104  
   105  // Config describes the config for this program
   106  type Config struct {
   107  	Tests    []Test
   108  	Backends []Backend
   109  }
   110  
   111  // NewConfig reads the config file
   112  func NewConfig(configFile string) (*Config, error) {
   113  	d, err := os.ReadFile(configFile)
   114  	if err != nil {
   115  		return nil, fmt.Errorf("failed to read config file: %w", err)
   116  	}
   117  	config := &Config{}
   118  	err = yaml.Unmarshal(d, &config)
   119  	if err != nil {
   120  		return nil, fmt.Errorf("failed to parse config file: %w", err)
   121  	}
   122  	// d, err = yaml.Marshal(&config)
   123  	// if err != nil {
   124  	// 	log.Fatalf("error: %v", err)
   125  	// }
   126  	// fmt.Printf("--- m dump:\n%s\n\n", string(d))
   127  	return config, nil
   128  }
   129  
   130  // MakeRuns makes Run objects for each combination of Backend and Test
   131  // in the config
   132  func (c *Config) MakeRuns() (runs Runs) {
   133  	for _, backend := range c.Backends {
   134  		for _, test := range c.Tests {
   135  			runs = append(runs, backend.MakeRuns(&test)...)
   136  		}
   137  	}
   138  	return runs
   139  }
   140  
   141  // Filter the Backends with the remotes passed in.
   142  //
   143  // If no backend is found with a remote is found then synthesize one
   144  func (c *Config) filterBackendsByRemotes(remotes []string) {
   145  	var newBackends []Backend
   146  	for _, name := range remotes {
   147  		found := false
   148  		for i := range c.Backends {
   149  			if c.Backends[i].Remote == name {
   150  				newBackends = append(newBackends, c.Backends[i])
   151  				found = true
   152  			}
   153  		}
   154  		if !found {
   155  			log.Printf("Remote %q not found - inserting with default flags", name)
   156  			// Lookup which backend
   157  			fsInfo, _, _, _, err := fs.ConfigFs(name)
   158  			if err != nil {
   159  				log.Fatalf("couldn't find remote %q: %v", name, err)
   160  			}
   161  			newBackends = append(newBackends, Backend{Backend: fsInfo.FileName(), Remote: name})
   162  		}
   163  	}
   164  	c.Backends = newBackends
   165  }
   166  
   167  // Filter the Backends with the backendNames passed in
   168  func (c *Config) filterBackendsByBackends(backendNames []string) {
   169  	var newBackends []Backend
   170  	for _, name := range backendNames {
   171  		for i := range c.Backends {
   172  			if c.Backends[i].Backend == name {
   173  				newBackends = append(newBackends, c.Backends[i])
   174  			}
   175  		}
   176  	}
   177  	c.Backends = newBackends
   178  }
   179  
   180  // Filter the incoming tests into the backends selected
   181  func (c *Config) filterTests(paths []string) {
   182  	var newTests []Test
   183  	for _, path := range paths {
   184  		for i := range c.Tests {
   185  			if c.Tests[i].Path == path {
   186  				newTests = append(newTests, c.Tests[i])
   187  			}
   188  		}
   189  	}
   190  	c.Tests = newTests
   191  }