package hw3test import ( "math/rand" "strings" "github.com/stretchr/testify/require" ) // LargePutPolicy keeps a small number of guaranteed successful writes above // the solution's memory limit, while bounding the remaining PUT bodies. type LargePutPolicy struct { RunSeed int64 LargeSizes []int64 OtherMaxBytes int64 } // QueriesGen contains config for generating queries. type QueriesGen struct { // Number of queries to generate. Count int GetFile bool // Allow GET requests for files. GetFileNoErrors bool // Disable requests for non-existing files. GetDirectory bool // Allow GET requests for directories. Compression bool // Allow compression in GET requests. Post bool // Allow POST requests. Put bool // Allow PUT requests. Delete bool // Allow DELETE requests. AllHeaders bool // Allow extra headers. LargePuts *LargePutPolicy } func (g *QueriesGen) Generate(t *TC, env *Env, gen *EnvGen, seeds []int64, opts RunOpts, runSeed int64) []Query { env = env.Clone() largePuts := 0 stats := &Stats{} env.RootDir.Stats("", stats) stats.Normalize() var methods []string if g.GetFile || g.GetDirectory { methods = append(methods, "GET") } if g.Post { methods = append(methods, "POST") } if g.Put { methods = append(methods, "PUT") } if g.Delete { methods = append(methods, "DELETE") } var queries []Query for _, seed := range seeds { r := rand.New(rand.NewSource(seed)) method := methods[r.Intn(len(methods))] var genPaths []string if len(stats.DirPaths) > 0 && !(method == "GET" && !g.GetDirectory) { genPaths = append(genPaths, stats.DirPaths[r.Intn(len(stats.DirPaths))]) genPaths = append(genPaths, stats.DirPaths[r.Intn(len(stats.DirPaths))]) } if len(stats.FilePaths) > 0 && !(method == "GET" && !g.GetFile) { genPaths = append(genPaths, stats.FilePaths[r.Intn(len(stats.FilePaths))]) genPaths = append(genPaths, stats.FilePaths[r.Intn(len(stats.FilePaths))]) } if !(method == "GET" && g.GetFileNoErrors) { // TODO: better non-existing path generator randomPath := gen.FilenameGen(r) + "/" + gen.FilenameGen(r) genPaths = append(genPaths, randomPath) if len(stats.DirPaths) > 0 { randomDir := stats.DirPaths[r.Intn(len(stats.DirPaths))] num := 2 if method == "POST" { num = 4 } for i := 0; i < num; i++ { genPaths = append(genPaths, randomDir+"/"+gen.FilenameGen(r)) } } } if len(genPaths) == 0 { continue } hostHeader := opts.ServerDomain if g.AllHeaders && r.Intn(5) == 0 { // to get 400 hostHeader = "hse.ru" } path := strings.TrimPrefix(genPaths[r.Intn(len(genPaths))], "/") if path == "" && method != "GET" { // Keep the existing large-file scenarios and RNG sequence. // Requests targeting the root are covered on a small tree in contract.go. path = "MISSING_ROOT_TARGET" } gzipRequested := g.Compression && r.Intn(2) == 1 query := Query{ Seed: seed, Method: method, Path: path, Gzip: method == "GET" && gzipRequested, CreateDirectory: method == "POST" && (r.Intn(2) == 1), RemoveDirectory: method == "DELETE" && (r.Intn(2) == 1), HostHeader: hostHeader, VerifyHeaders: g.AllHeaders, } if (method == "POST" && !query.CreateDirectory) || method == "PUT" { query.FileContent = gen.GenerateFile(r) } action := query.Action(env, &opts) if query.Method == "PUT" && g.LargePuts != nil { policy := g.LargePuts if _, ok := action.(ReplaceFileAction); ok && runSeed == policy.RunSeed && largePuts < len(policy.LargeSizes) { query.FileContent.Size = policy.LargeSizes[largePuts] largePuts++ } else if query.FileContent.Size > policy.OtherMaxBytes { query.FileContent.Size = policy.OtherMaxBytes } } queries = append(queries, query) if action != nil { changed := action.ApplyEnv(t, env) if changed { stats = &Stats{} env.RootDir.Stats("", stats) stats.Normalize() } } } if g.LargePuts != nil && runSeed == g.LargePuts.RunSeed { require.Equal(t, len(g.LargePuts.LargeSizes), largePuts, "not enough successful PUT queries for large-file coverage") } return queries }