Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonBaeumer committed Feb 22, 2019
0 parents commit 2a816b4
Show file tree
Hide file tree
Showing 56 changed files with 16,463 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# make github know about vendored code
# https://github.com/github/linguist#vendored-code
**/vendor/** linguist-vendored
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
commander
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build:
go build cmd/commander/commander.go

test:
go test ./...
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Commander

Testing tool for command line applications.

## Usage

```
$ make build
$ ./commander ./example/commander.yaml
✓ more printing
✓ it should print hello world
✓ it should print something
```

## Todo:
- command execution
- environment variables
- arguments?
- timeout
- exit code
- stdout
- Validate against string
- Validate against file
- Validate against line
- Validate with wildcards / regex
- stderr
- Validate against string
- Validate against file
- Validate with wildcards
- testing interactive applications?
- Support different os
- Windows
- MacOs
- Linux
- debian
- ubuntu
- rhel
- centos
- alpine

## Open

- support for...
- docker
- docker-compose
- lxc
- vagrant

## Architecture

- runtime?
- test-executer
- ordering?
- interpreter?
12 changes: 12 additions & 0 deletions cmd/commander/commander.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"github.com/SimonBaeumer/commander/pkg"
"github.com/SimonBaeumer/commander/pkg/runtime"
"os"
)

func main() {
suite := commander.ParseYAMLFile(os.Args[1])
runtime.Start(suite)
}
13 changes: 13 additions & 0 deletions examples/commander.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
tests:
"it should print hello world":
command: "echo hello world"
stdout: hello world
exit-code: 0
"it should print something":
command: "echo soething"
stdout: something
exit-code: 0
"more printing":
command: "echo soething"
stdout: something
exit-code: 1
13 changes: 13 additions & 0 deletions examples/simple_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

@test "heyho" {
export ENV_TEST="heyho"

run echo "hello world"

assert $output "test"
assert $line[0] "test"
assert $output ./example.out
assert $status SUCCESS
assert $status 127
}
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module github.com/SimonBaeumer/commander

require (
github.com/stretchr/testify v1.3.0
gopkg.in/yaml.v2 v2.2.2
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5 changes: 5 additions & 0 deletions pkg/_fixtures/commander.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
tests:
"it should print hello world":
command: "echo hello world"
stdout: hello world
exit-code: 0
111 changes: 111 additions & 0 deletions pkg/runtime/runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package runtime

import (
"bytes"
"fmt"
"github.com/SimonBaeumer/commander/pkg"
"log"
"os/exec"
"strings"
)

type Command struct {
cmd string
args string
exitCode int
stderr string
stdout string

//env
//timeout
//...
}

// Start starts the given test suite
func Start(suite commander.Suite) {
c := make(chan commander.TestCase)

for _, t := range suite.GetTestCases() {
go runTest(t, c)
}

printResults(c, suite)
}

func printResults(c chan commander.TestCase, suite commander.Suite) {
counter := 0
for r := range c {
// Validate result
if !r.Result.Success {
fmt.Println("✗ ", r.Title)
} else {
fmt.Println("✓ ", r.Title)
}

counter++
if (counter >= len(suite.GetTestCases())) {
close(c)
}
}
}

func runTest(test commander.TestCase, results chan<- commander.TestCase) {
// Create command
cmd := compile(test.Command)

// Execute command
if err := cmd.Execute(); err != nil {
log.Fatal(err)
}

// Write test result
test.Result = commander.TestResult{
ExitCode: cmd.exitCode,
Stdout: cmd.stdout,
Stderr: cmd.stderr,
}

result := Validate(test)
test.Result.Success = result.Success
test.Result.FailureProperty = result.Property

// Send to result channel
results <- test
}

func compile(command string) *Command {
parts := strings.Split(command, " ")
executable := parts[0]

splitArgs := append(parts[:0], parts[1:]...)
args := strings.Join(splitArgs, " ")

return &Command{
cmd: executable,
args: args,
}
}

// Execute executes a command on the system
func (c *Command) Execute() error {
cmd := exec.Command(c.cmd, c.args)

var (
outBuff bytes.Buffer
errBuff bytes.Buffer
)
cmd.Stdout = &outBuff
cmd.Stderr = &errBuff

err := cmd.Run()
if err != nil {
return err
} else {
c.exitCode = 0
}

c.stderr = errBuff.String()
c.stdout = outBuff.String()

return nil
}
47 changes: 47 additions & 0 deletions pkg/runtime/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package runtime

import "github.com/SimonBaeumer/commander/pkg"

type ValidationResult struct {
Success bool
Property string
}

func Validate(test commander.TestCase) ValidationResult {
r := ValidationResult{}

result := validateOutput(test.Stdout, test.Result.Stdout)
if !result {
r.Success = result
test.Result.FailureProperty = commander.Stdout
}

result = validateOutput(test.Stderr, test.Result.Stderr)
if !result {
r.Success = result
r.Property = commander.Stderr
}

result = validateExitCode(test.ExitCode, test.Result.ExitCode)
if !result {
r.Success = result
r.Property = commander.ExitCode
}

r.Success = true
return r
}

func validateOutput(expected string, actual string) bool {
if expected != actual {
return false
}
return true
}

func validateExitCode(expected int, actual int) bool {
if expected != actual {
return false
}
return true
}
32 changes: 32 additions & 0 deletions pkg/suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package commander

const (
ExitCode = "ExitCode"
Stdout = "Stdout"
Stderr = "Stderr"
)

// TestCase represents a test case which will be executed by the runtime
type TestCase struct {
Title string
Command string
Stdout string
Stderr string
ExitCode int
Result TestResult
}

// TestResult holds the result for a specific test
type TestResult struct {
Success bool
//Skipped bool
Stdout string
Stderr string
ExitCode int
FailureProperty string
}

// Suite
type Suite interface {
GetTestCases() []TestCase
}
Loading

0 comments on commit 2a816b4

Please sign in to comment.