func makeRequest(scenarios []Scenario, rate float64, requests chan bender.Test, stop chan bool, logger *log.Logger) ([]*pool, error) {
	selector := make([]int, 100)
	pools := make([]*pool, len(scenarios))
	cummulatedPercentage := 0
	for i, s := range scenarios {
		pool := pool{
			Scenario: s,
			No:       i,
			Chan:     make(chan bender.Test, 2),
			wg:       &sync.WaitGroup{},
			mu:       &sync.Mutex{},
		}
		pools[i] = &pool
		pools[i].newThread(stop, logger)
		for k := 0; k < s.Percentage; k++ {
			if cummulatedPercentage+k > 99 {
				return nil, fmt.Errorf("suite: sum of Percentage greater than 100%%")
			}
			selector[cummulatedPercentage+k] = i
		}
		cummulatedPercentage += s.Percentage
	}
	if cummulatedPercentage <= 99 {
		return nil, fmt.Errorf("suite: sum of Percentage less than 100%%")
	}
	gracetime := time.Second / time.Duration(5*rate)
	go func() {
		counter := 0
		for {
			rn := rand.Intn(100)
			pool := pools[selector[rn]]
			var test bender.Test
			select {
			case <-stop:
				logger.Println("Request generation stopped.")
				return
			case test = <-pool.Chan:
				counter++
				requests <- test
			default:
				pool.newThread(stop, logger)
				time.Sleep(gracetime)
			}
		}
	}()
	for i := range scenarios {
		pools[i].newThread(stop, logger)
	}
	logger.Println("Request generation started.")
	return pools, nil
}
makeRequests is responsible for generating a stream of request and providing
these requests on the requests channel until the stop channel is closed.
The request are drawn randoemly from the given scenarios (while each suite
the scenario consists of executes linearely on each thread).
The thread pool of the scenarios is returned for cleanup purpose.
package suite
import (
	"bufio"
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/vdobler/ht/cookiejar"
	"github.com/vdobler/ht/errorlist"
	"github.com/vdobler/ht/ht"
	"github.com/vdobler/ht/internal/bender"
)
type Scenario struct {
	Name string
	*RawSuite
	Percentage int
	MaxThreads int
	OmitChecks bool
	globals map[string]string
	jar     *cookiejar.Jar
}
func (sc *Scenario) setup(logger *log.Logger) *Suite {
	suite := NewFromRaw(sc.RawSuite, sc.globals, sc.jar, logger)
	suite.tests = suite.tests[:len(sc.RawSuite.Setup)]
	i := 0
	executor := func(test *ht.Test) error {
		i++
		test.SetMetadata("SeqNo", fmt.Sprintf("Setup-%02d", i))
		if test.Result.Status == ht.Bogus || test.Result.Status == ht.Skipped {
			return nil
		}
		if !sc.RawSuite.tests[i-1].IsEnabled() {
			test.Result.Status = ht.Skipped
			return nil
		}
		test.Run()
		if test.Result.Status > ht.Pass {
			return ErrAbortExecution
		}
		return nil
	}
	suite.Iterate(executor)
	sc.jar = suite.Jar
	sc.globals = suite.FinalVariables
	return suite
}
func (sc *Scenario) teardown(logger *log.Logger) *Suite {
	suite := NewFromRaw(sc.RawSuite, sc.globals, sc.jar, logger)
	suite.tests = suite.tests[len(suite.tests)-len(sc.RawSuite.Teardown):]
	i := 0
	executor := func(test *ht.Test) error {
		i++
		test.SetMetadata("SeqNo", fmt.Sprintf("Teardown-%02d", i))
		if test.Result.Status == ht.Bogus || test.Result.Status == ht.Skipped {
			return nil
		}
		if !sc.RawSuite.tests[i-1].IsEnabled() {
			test.Result.Status = ht.Skipped
			return nil
		}
		test.Run()
		return nil
	}
	suite.Iterate(executor)
	sc.jar = suite.Jar
	sc.globals = suite.FinalVariables
	return suite
}
type pool struct {
	Scenario
	No      int  
	Chan    chan bender.Test
	wg      *sync.WaitGroup
	mu      *sync.Mutex
	Threads int
	Misses  int
}
var IDSep = "\u2055"  
func (p *pool) newThread(stop chan bool, logger *log.Logger) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.MaxThreads > 0 && p.Threads >= p.MaxThreads {
		if p.Scenario.Verbosity >= 2 {
			logger.Printf("Scenario %d %q: No extra thread started (%d already running)\n",
				p.No+1, p.Scenario.Name, p.Threads)
		}
		p.Misses++
		return
	}
	p.Threads++
	if p.Scenario.Verbosity >= 1 {
		logger.Printf("Scenario %d %q: Starting new thread %d\n",
			p.No+1, p.Scenario.Name, p.Threads)
	}
	p.wg.Add(1)
	go func(thread int) {
		thglobals := make(map[string]string, len(p.globals)+2)
		for n, v := range p.globals {
			thglobals[n] = v
		}
		thglobals["THREAD"] = strconv.Itoa(thread)
		repetition := 1
		done := false
		for !done {
			select {
			case <-stop:
				done = true
			default:
			}
			if done {
				break
			}
			thglobals["REPETITION"] = strconv.Itoa(repetition)
			executed := make(chan bool)
			t := 0
			executor := func(test *ht.Test) error {
				t++
				ti := TestIdentifier{
					Scenario:     p.No + 1,
					Thread:       thread,
					Repetition:   repetition,
					Test:         t,
					ScenarioName: p.Scenario.Name,
					TestName:     test.Name,
				}
				test.Name = ti.String()
				test.SetMetadata("Identifier", ti)
				if !p.Scenario.RawSuite.tests[t-1].IsEnabled() {
					test.Result.Status = ht.Skipped
					return nil
				}
				select {
				case <-stop:
					done = true
					return ErrAbortExecution
				case p.Chan <- bender.Test{Test: test, Done: executed}:
					<-executed
				}
				return nil
			}
			suite := NewFromRaw(p.Scenario.RawSuite, thglobals, nil, logger)
			nSetup, nMain := len(p.Scenario.RawSuite.Setup), len(p.Scenario.RawSuite.Main)
			suite.tests = suite.tests[nSetup : nSetup+nMain]
			suite.Iterate(executor)
			if p.Scenario.Verbosity >= 2 {
				logger.Printf("Scenario %d %q: Finished repetition %d of thread %d: %s\n",
					p.No+1, p.Scenario.Name, repetition, thread, suite.Status)
			}
			repetition += 1
		}
		if p.Scenario.Verbosity >= 1 {
			logger.Printf("Scenario %d %q: Done with thread %d",
				p.No+1, p.Scenario.Name, thread)
		}
		p.wg.Done()
	}(p.Threads)
}