commander-cli/commander

View on GitHub
pkg/runtime/runner.go

Summary

Maintainability
A
55 mins
Test Coverage
A
91%
package runtime

import (
    "fmt"
    "log"
    "sync"
    "time"
)

// Runner holds the config and executes the desired runtime env
type Runner struct {
    Nodes []Node
}

// Run the runner
func (r *Runner) Run(tests []TestCase) <-chan TestResult {
    in := make(chan TestCase)
    out := make(chan TestResult)

    go func(tests []TestCase) {
        defer close(in)
        for _, t := range tests {
            in <- t
        }
    }(tests)

    var wg sync.WaitGroup
    wg.Add(1)

    go func(tests chan TestCase) {
        defer wg.Done()

        for t := range tests {
            // If no node was set use local mode as default
            if len(t.Nodes) == 0 {
                t.Nodes = []string{"local"}
            }

            for _, n := range t.Nodes {
                result := TestResult{}
                for i := 1; i <= t.Command.GetRetries(); i++ {

                    if t.Skip {
                        result = TestResult{TestCase: t, Skipped: true, Node: n}
                        break
                    }

                    e := r.getExecutor(n)
                    result = e.Execute(t)
                    result.Node = n
                    result.Tries = i

                    if result.ValidationResult.Success {
                        break
                    }

                    executeRetryInterval(t)
                }
                out <- result
            }
        }
    }(in)

    go func(results chan TestResult) {
        wg.Wait()
        close(results)
    }(out)

    return out
}

// getExecutor gets the node by the name it matches within the runner config
func (r *Runner) getExecutor(node string) Executor {
    for _, n := range r.Nodes {
        if n.Name == node {
            switch n.Type {
            case "ssh":
                return NewSSHExecutor(n.Addr, n.User, WithIdentityFile(n.IdentityFile), WithPassword(n.Pass))
            case "local", "":
                return NewLocalExecutor()
            case "docker":
                log.Println("Use docker executor")
                return DockerExecutor{
                    Image:        n.Image,
                    Privileged:   n.Privileged,
                    ExecUser:     n.DockerExecUser,
                    RegistryPass: n.Pass,
                    RegistryUser: n.User,
                }
            default:
                log.Fatalf("Node type %s not found for node %s", n.Type, n.Name)
            }
        }
    }

    log.Fatalf("Node %s not found", node)
    return NewLocalExecutor()
}

func executeRetryInterval(t TestCase) {
    if t.Command.GetRetries() > 1 && t.Command.Interval != "" {
        interval, err := time.ParseDuration(t.Command.Interval)
        if err != nil {
            panic(fmt.Sprintf("'%s' interval error: %s", t.Command.Cmd, err))
        }
        time.Sleep(interval)
    }
}

// GetRetries returns the retries of the command
func (c *CommandUnderTest) GetRetries() int {
    if c.Retries == 0 {
        return 1
    }
    return c.Retries
}