diff --git a/Makefile b/Makefile index 0fbf5121c..9c9f07960 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test_reconnect: validate_examples: go run dev/update-examples-deps/main.go - bash dev/validate_examples.sh + go run dev/validate-examples/main.go fmt: diff --git a/_examples/cqrs-protobuf/.validate_example.sh b/_examples/cqrs-protobuf/.validate_example.sh deleted file mode 100644 index 63c030d58..000000000 --- a/_examples/cqrs-protobuf/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="beers ordered to room 3" diff --git a/_examples/cqrs-protobuf/.validate_example.yml b/_examples/cqrs-protobuf/.validate_example.yml new file mode 100644 index 000000000..edbcefd0f --- /dev/null +++ b/_examples/cqrs-protobuf/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "beers ordered to room 3" diff --git a/_examples/http-to-kafka/.validate_example.sh b/_examples/http-to-kafka/.validate_example.sh deleted file mode 100644 index 19554e7fa..000000000 --- a/_examples/http-to-kafka/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="Starting handler" diff --git a/_examples/http-to-kafka/.validate_example.yml b/_examples/http-to-kafka/.validate_example.yml new file mode 100644 index 000000000..6d0a33528 --- /dev/null +++ b/_examples/http-to-kafka/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "Starting handler" diff --git a/_examples/kafka-to-http/.validate_example.sh b/_examples/kafka-to-http/.validate_example.sh deleted file mode 100644 index d999080bb..000000000 --- a/_examples/kafka-to-http/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="POST /foo_or_bar: message" diff --git a/_examples/kafka-to-http/.validate_example.yml b/_examples/kafka-to-http/.validate_example.yml new file mode 100644 index 000000000..1e3d3abdc --- /dev/null +++ b/_examples/kafka-to-http/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "POST /foo_or_bar: message" diff --git a/_examples/metrics/.validate_example.sh b/_examples/metrics/.validate_example.sh deleted file mode 100644 index d24d1c80b..000000000 --- a/_examples/metrics/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="msg=\"Message acked\"" diff --git a/_examples/metrics/.validate_example.yml b/_examples/metrics/.validate_example.yml new file mode 100644 index 000000000..1ef92d09a --- /dev/null +++ b/_examples/metrics/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "msg=\"Message acked\"" diff --git a/_examples/simple-app/.validate_example_publishing.sh b/_examples/simple-app/.validate_example_publishing.sh deleted file mode 100644 index 808c99df1..000000000 --- a/_examples/simple-app/.validate_example_publishing.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="msg=\"Message sent to Kafka\"" diff --git a/_examples/simple-app/.validate_example_publishing.yml b/_examples/simple-app/.validate_example_publishing.yml new file mode 100644 index 000000000..93b21ff8c --- /dev/null +++ b/_examples/simple-app/.validate_example_publishing.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "msg=\"Message sent to Kafka\"" diff --git a/_examples/simple-app/.validate_example_subscribing.sh b/_examples/simple-app/.validate_example_subscribing.sh deleted file mode 100644 index 1eac20413..000000000 --- a/_examples/simple-app/.validate_example_subscribing.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="msg=\"Starting handler\"" diff --git a/_examples/simple-app/.validate_example_subscribing.yml b/_examples/simple-app/.validate_example_subscribing.yml new file mode 100644 index 000000000..34613422d --- /dev/null +++ b/_examples/simple-app/.validate_example_subscribing.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "msg=\"Starting handler\"" diff --git a/_examples/your-first-app/.validate_example.sh b/_examples/your-first-app/.validate_example.sh deleted file mode 100644 index 24c6e9e55..000000000 --- a/_examples/your-first-app/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="received event [0-9]+" diff --git a/_examples/your-first-app/.validate_example.yml b/_examples/your-first-app/.validate_example.yml new file mode 100644 index 000000000..d0358a4fb --- /dev/null +++ b/_examples/your-first-app/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "received event [0-9]+" diff --git a/dev/validate-examples/go.mod b/dev/validate-examples/go.mod new file mode 100644 index 000000000..31e12fe96 --- /dev/null +++ b/dev/validate-examples/go.mod @@ -0,0 +1,5 @@ +module github.com/ThreeDotsLabs/watermill/dev/validate-examples + +go 1.12 + +require gopkg.in/yaml.v2 v2.2.2 // indirect diff --git a/dev/validate-examples/go.sum b/dev/validate-examples/go.sum new file mode 100644 index 000000000..bd555a333 --- /dev/null +++ b/dev/validate-examples/go.sum @@ -0,0 +1,3 @@ +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= diff --git a/dev/validate-examples/main.go b/dev/validate-examples/main.go new file mode 100644 index 000000000..839184bb9 --- /dev/null +++ b/dev/validate-examples/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "time" + + yaml "gopkg.in/yaml.v2" +) + +type Config struct { + ValidationCmd string `yaml:"validation_cmd"` + TeardownCmd string `yaml:"teardown_cmd"` + Timeout int `yaml:"timeout"` + ExpectedOutput string `yaml:"expected_output"` +} + +func (c *Config) LoadFrom(path string) error { + file, err := ioutil.ReadFile(path) + if err != nil { + return err + } + err = yaml.Unmarshal(file, c) + if err != nil { + return err + } + return nil +} + +func main() { + walkErr := filepath.Walk(".", func(exampleConfig string, f os.FileInfo, _ error) error { + matches, _ := filepath.Match(".validate_example*.yml", f.Name()) + if !matches { + return nil + } + + exampleDirectory := filepath.Dir(exampleConfig) + ok, err := validate(exampleConfig) + + if err != nil { + fmt.Printf("validation for %s failed, err: %v\n", exampleDirectory, err) + return nil + } + + if ok { + fmt.Printf("validation for %s succeeded\n", exampleDirectory) + return nil + } + + fmt.Printf("validation for %s failed\n", exampleDirectory) + return nil + }) + if walkErr != nil { + panic(walkErr) + } + +} + +func validate(path string) (bool, error) { + config := &Config{} + err := config.LoadFrom(path) + if err != nil { + return false, fmt.Errorf("could not load config, err: %v", err) + } + + cmdAndArgs := strings.Fields(config.ValidationCmd) + validationCmd := exec.Command(cmdAndArgs[0], cmdAndArgs[1:]...) + validationCmd.Dir = filepath.Dir(path) + defer func() { + if config.TeardownCmd == "" { + return + } + cmdAndArgs := strings.Fields(config.TeardownCmd) + teardownCmd := exec.Command(cmdAndArgs[0], cmdAndArgs[1:]...) + teardownCmd.Dir = filepath.Dir(path) + _ = teardownCmd.Run() + }() + + stdout, err := validationCmd.StdoutPipe() + if err != nil { + return false, fmt.Errorf("could not attach to stdout, err: %v", err) + } + + err = validationCmd.Start() + if err != nil { + return false, fmt.Errorf("could not start validation, err: %v", err) + } + + success := make(chan bool) + + go func() { + output := bufio.NewReader(stdout) + for { + line, _, err := output.ReadLine() + if err != nil { + if err == io.EOF { + break + } + } + ok, _ := regexp.Match(config.ExpectedOutput, line) + if ok { + success <- true + return + } + } + success <- false + }() + + select { + case success := <-success: + return success, nil + case <-time.After(time.Duration(config.Timeout) * time.Second): + return false, fmt.Errorf("validation command timed out") + } +} diff --git a/dev/validate_examples.sh b/dev/validate_examples.sh deleted file mode 100755 index fb2173440..000000000 --- a/dev/validate_examples.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -# DISCLAIMER -# -# The timeouts in this file are arbitrary and may not be reliable. -# Thus, it is not suitable for CI, rather to be run locally by developers -# to ensure that their changes didn't break existing examples/snippets. -# -# If any code check fails, investigate the log to find out about the cause. - -set -e - -function enumerate() { - msg=$1 - # message in green - echo -e "\e[32m\t✓ $msg\e[39m" -} - -function pass() { - # light green - echo -e "\e[92m\tPASS\e[39m" - tput sgr0 -} - -function fail() { - # red - echo -e "\e[31m\tFAIL\e[39m" -} - -# check_output runs a selected command in the caller's working directory for a defined time; -# It looks in the logs for a defined phrase. The phrase may be a grep-compatible regexp. -# -# Returns 0 if the phrase is found before the timeout. -# Returns the error code from the command if it ended in an error. -# Returns 125 if the requested phrase was not found in output. -function check_output() { - cmd=$1 - timeout=$2 - look_for=$3 - - # prepare the log dump - output=$(mktemp) - - # run the command and dump the logs - echo "$(pwd)" - echo "timeout $timeout "$cmd" &> "$output"" - timeout $timeout $cmd &> $output - exitCode=$? - - if [ "$exitCode" -eq 124 ] - then - echo "Command timed out in ${timeout}s" - elif [ "$exitCode" -ne 0 ] - then - echo "Command exited with error $exitCode" - rm "$output" - return $exitCode - fi - - # check the logs for the defined phrase - echo "Checking logs for $look_for" - phrase="$(grep -E "$look_for" "$output")" || true - - if [ -z "$phrase" ] - then - echo "Phrase $look_for not found in output" - echo "$output left for inspection" - return 125 - else - echo "Found phrase $look_for in output:" - echo "$phrase" - rm "$output" - return - fi -} - -function check_examples() { - anyError=0 - - echo "Checking output of snippets and examples..." - - for conf in $(find . -name ".validate_example*.sh") - do - dir="$(dirname $conf)" - # we expect $conf to supply $CMD, $TIMEOUT and $EXPECTED_OUTPUT - source "$conf" - pushd $dir &> /dev/null - enumerate "$conf" - wrap_check_output "$CMD" $TIMEOUT "$EXPECTED_OUTPUT" || anyError=1 - popd &> /dev/null - unset CMD && unset TIMEOUT && unset EXPECTED_OUTPUT - done - - - echo "...done" - return $anyError -} - -function wrap_check_output() { - RESULT=$(check_output "$@") - - if [[ "$?" -eq 0 ]] - then - pass - else - echo -e "\e[91m$RESULT\e[39m" # light red - fail - anyError=1 - fi - - return $anyError -} - -if [ "$0" = "$BASH_SOURCE" ] -then -# script executed directly, not sourced - anyError=0 - - check_examples || anyError=1 - exit $anyError -fi - diff --git a/docs/content/docs/getting-started/amqp/.validate_example.sh b/docs/content/docs/getting-started/amqp/.validate_example.sh deleted file mode 100644 index 8ef8e3dc1..000000000 --- a/docs/content/docs/getting-started/amqp/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="received message: [0-9a-f\\-]+, payload: Hello, world!" diff --git a/docs/content/docs/getting-started/amqp/.validate_example.yml b/docs/content/docs/getting-started/amqp/.validate_example.yml new file mode 100644 index 000000000..f8df014ca --- /dev/null +++ b/docs/content/docs/getting-started/amqp/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "received message: [0-9a-f\\-]+, payload: Hello, world!" diff --git a/docs/content/docs/getting-started/go-channel/.validate_example.sh b/docs/content/docs/getting-started/go-channel/.validate_example.sh deleted file mode 100644 index 2e1c2fc9b..000000000 --- a/docs/content/docs/getting-started/go-channel/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="go run main.go" -# how long to wait for the output -TIMEOUT=1 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="payload: Hello, world!" diff --git a/docs/content/docs/getting-started/go-channel/.validate_example.yml b/docs/content/docs/getting-started/go-channel/.validate_example.yml new file mode 100644 index 000000000..f75a0bf19 --- /dev/null +++ b/docs/content/docs/getting-started/go-channel/.validate_example.yml @@ -0,0 +1,3 @@ +validation_cmd: "docker-compose up" +timeout: 1 +expected_output: "payload: Hello, world!" diff --git a/docs/content/docs/getting-started/googlecloud/.validate_example.sh b/docs/content/docs/getting-started/googlecloud/.validate_example.sh deleted file mode 100644 index 3d7a25efc..000000000 --- a/docs/content/docs/getting-started/googlecloud/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="payload: Hello, world!" diff --git a/docs/content/docs/getting-started/googlecloud/.validate_example.yml b/docs/content/docs/getting-started/googlecloud/.validate_example.yml new file mode 100644 index 000000000..146b39f16 --- /dev/null +++ b/docs/content/docs/getting-started/googlecloud/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "payload: Hello, world!" diff --git a/docs/content/docs/getting-started/kafka/.validate_example.sh b/docs/content/docs/getting-started/kafka/.validate_example.sh deleted file mode 100644 index f95e0b338..000000000 --- a/docs/content/docs/getting-started/kafka/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=60 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="payload: Hello, world!" diff --git a/docs/content/docs/getting-started/kafka/.validate_example.yml b/docs/content/docs/getting-started/kafka/.validate_example.yml new file mode 100644 index 000000000..7f97a98c0 --- /dev/null +++ b/docs/content/docs/getting-started/kafka/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 60 +expected_output: "payload: Hello, world!" diff --git a/docs/content/docs/getting-started/nats-streaming/.validate_example.sh b/docs/content/docs/getting-started/nats-streaming/.validate_example.sh deleted file mode 100644 index 3d7a25efc..000000000 --- a/docs/content/docs/getting-started/nats-streaming/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="payload: Hello, world!" diff --git a/docs/content/docs/getting-started/nats-streaming/.validate_example.yml b/docs/content/docs/getting-started/nats-streaming/.validate_example.yml new file mode 100644 index 000000000..146b39f16 --- /dev/null +++ b/docs/content/docs/getting-started/nats-streaming/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "payload: Hello, world!" diff --git a/docs/content/docs/getting-started/router/.validate_example.sh b/docs/content/docs/getting-started/router/.validate_example.sh deleted file mode 100644 index 309767d56..000000000 --- a/docs/content/docs/getting-started/router/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="go run main.go" -# how long to wait for the output -TIMEOUT=3 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="structHandler received message [0-9a-f\\-]+" diff --git a/docs/content/docs/getting-started/router/.validate_example.yml b/docs/content/docs/getting-started/router/.validate_example.yml new file mode 100644 index 000000000..0977a6bcc --- /dev/null +++ b/docs/content/docs/getting-started/router/.validate_example.yml @@ -0,0 +1,3 @@ +validation_cmd: "go run main.go" +timeout: 3 +expected_output: "structHandler received message [0-9a-f\\-]+" diff --git a/docs/content/docs/message/.validate_example.yml b/docs/content/docs/message/.validate_example.yml new file mode 100644 index 000000000..3b31cc305 --- /dev/null +++ b/docs/content/docs/message/.validate_example.yml @@ -0,0 +1,3 @@ +validation_cmd: "go run receiving-ack.go" +timeout: 1 +expected_output: "ack received" diff --git a/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.sh b/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.sh deleted file mode 100644 index 8ef8e3dc1..000000000 --- a/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.sh +++ /dev/null @@ -1,8 +0,0 @@ -# configuration for the dev/validate_example script. -# -# how to run the command -CMD="docker-compose up" -# how long to wait for the output -TIMEOUT=30 -# we expect this regexp to be present in the output -EXPECTED_OUTPUT="received message: [0-9a-f\\-]+, payload: Hello, world!" diff --git a/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.yml b/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.yml new file mode 100644 index 000000000..f8df014ca --- /dev/null +++ b/docs/content/docs/snippets/amqp-consumer-groups/.validate_example.yml @@ -0,0 +1,4 @@ +validation_cmd: "docker-compose up" +teardown_cmd: "docker-compose down" +timeout: 30 +expected_output: "received message: [0-9a-f\\-]+, payload: Hello, world!"