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 }