runn

package module
v0.12.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2022 License: MIT Imports: 32 Imported by: 6

README

runn

runn ( means "Run N" ) is a package/tool for running operations following a scenario.

Key features of runn are:

  • As a tool for scenario testing.
  • As a test helper package for the Go language.
  • As a tool for automation.

Usage

runn can run a multi-step scenario following a runbook written in YAML format.

As a tool for scenario testing / As a tool for automation.

runn can run one or more runbooks.

$ runn list path/to/**/*.yml
  Desc                     Path
-----------------------------------------------------
  Login and get projects.  path/to/books/login.yml
  Login and logout.        path/to/books/logout.yml
  New project.             path/to/books/new.yml
$ runn run path/to/**/*.yml
Login and get projects. ... ok
Login and logout. ... ok
New project. ... ok

3 scenarios, 0 failures
As a test helper package for the Go language.

runn can also behave as a test helper for the Go language.

Run N runbooks using httptest.Server
func TestRouter(t *testing.T) {
	ctx := context.Background()
	db, err := sql.Open("postgres", "user=root password=root host=localhost dbname=test sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	ts := httptest.NewServer(NewRouter(db))
	t.Cleanup(func() {
		ts.Close()
		db.Close()
	})
	o, err := runn.Load("testdata/books/**/*.yml", runn.T(t), runn.Runner("req", ts.URL), runn.DBRunner("db", db))
	if err != nil {
		t.Fatal(err)
	}
	if err := o.RunN(ctx); err != nil {
		t.Fatal(err)
	}
}
Run single runbook using httptest.Server
func TestRouter(t *testing.T) {
	ctx := context.Background()
	db, err := sql.Open("postgres", "user=root password=root host=localhost dbname=test sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	ts := httptest.NewServer(NewRouter(db))
	t.Cleanup(func() {
		ts.Close()
		db.Close()
	})
	o, err := runn.New(runn.T(t), runn.Book("testdata/books/login.yml"), runn.Runner("req", ts.URL), runn.DBRunner("db", db))
	if err != nil {
		t.Fatal(err)
	}
	if err := o.Run(ctx); err != nil {
		t.Fatal(err)
	}
}
Run N runbooks with http.Handler
func TestRouter(t *testing.T) {
	ctx := context.Background()
	db, err := sql.Open("postgres", "user=root password=root host=localhost dbname=test sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	t.Cleanup(func() {
		db.Close()
	})
	o, err := runn.Load("testdata/books/**/*.yml", runn.T(t), runn.HTTPRunnerWithHandler("req", NewRouter(db)), runn.DBRunner("db", db))
	if err != nil {
		t.Fatal(err)
	}
	if err := o.RunN(ctx); err != nil {
		t.Fatal(err)
	}
}

Runbook

The runbook file has the following format.

step: section accepts array or ordered map.

Array
desc: Login and get projects.
runners:
  req: https://example.com/api/v1
  db: mysql://root:mypass@localhost:3306/testdb
vars:
  username: alice
steps:
  -
    db:
      query: SELECT * FROM users WHERE name = '{{ vars.username }}'
  -
    req:
      /login:
        post:
          body:
            application/json:
              email: "{{ steps[0].rows[0].email }}"
              password: "{{ steps[0].rows[0].password }}"
  -
    test: steps[1].res.status == 200
  -
    req:
      /projects:
        get:
          headers:
            Authorization: "token {{ steps[1].res.body.session_token }}"
          body: null
  -
    test: steps[3].res.status == 200
  -
    test: len(steps[3].res.body.projects) > 0
Map
desc: Login and get projects.
runners:
  req: https://example.com/api/v1
  db: mysql://root:mypass@localhost:3306/testdb
vars:
  username: alice
steps:
  find_user:
    db:
      query: SELECT * FROM users WHERE name = '{{ vars.username }}'
  login:
    req:
      /login:
        post:
          body:
            application/json:
              email: "{{ steps.find_user.rows[0].email }}"
              password: "{{ steps.find_user.rows[0].password }}"
  login_should_be_ok:
    test: steps.login.res.status == 200
  list_projects:
    req:
      /projects:
        get:
          headers:
            Authorization: "token {{ steps.login.res.body.session_token }}"
          body: null
  list_projects_should_be_ok:
    test: steps.list_projects.res.status == 200
  count_projects:
    test: len(steps.list_projects.res.body.projects) > 0

Array

color

Map

color

desc:

Description of runbook.

runners:

Mapping of runners that run steps: of runbook.

In the steps: section, call the runner with the key specified in the runners: section.

Built-in runners such as test runner do not need to be specified in this section.

runners:
  ghapi: ${GITHUB_API_ENDPOINT}
  idp: https://auth.example.com
  db: my:dbuser:${DB_PASS}@hostname:3306/dbname

In the example, each runner can be called by ghapi:, idp: or db: in steps:.

vars:

Mapping of variables available in the steps: of runbook.

vars:
  username: alice@example.com
  token: ${SECRET_TOKEN}

In the example, each variable can be used in {{ vars.username }} or {{ vars.token }} in steps:.

debug:

Enable debug output for runn.

debug: true
steps:

Steps to run in runbook.

The steps are invoked in order from top to bottom.

Any return values are recorded for each step.

When steps: is array, recorded values can be retrieved with {{ steps[*].* }}.

steps:
  -
    db:
      query: SELECT * FROM users WHERE name = '{{ vars.username }}'
  -
    req:
      /users/{{ steps[0].rows[0].id }}:
        get:
          body: null

When steps: is map, recorded values can be retrieved with {{ steps.<key>.* }}.

steps:
  find_user:
    db:
      query: SELECT * FROM users WHERE name = '{{ vars.username }}'
  user_info:
    req:
      /users/{{ steps.find_user.rows[0].id }}:
        get:
          body: null

Runner

HTTP Runner: Do HTTP request

Use https:// or http:// scheme to specify HTTP Runner.

When the step is invoked, it sends the specified HTTP Request and records the response.

runners:
  ghapi: https://api.github.com
DB Runner: Query a database

Use dsn (Data Source Name) to specify DB Runner.

When step is executed, it executes the specified query the database.

If the query is a SELECT clause, it records the selected rows, otherwise it records last_insert_id and rows_affected .

Support Databases

PostgreSQL:

runners:
  mydb: postgres://dbuser:dbpass@hostname:5432/dbname
runners:
  db: pg://dbuser:dbpass@hostname:5432/dbname

MySQL:

runners:
  testdb: mysql://dbuser:dbpass@hostname:3306/dbname
runners:
  db: my://dbuser:dbpass@hostname:3306/dbname

SQLite3:

runners:
  db: sqlite:///path/to/dbname.db
runners:
  local: sq://dbname.db
Exec Runner: execute command

The exec runner is a built-in runner, so there is no need to specify it in the runners: section.

It execute command using command: and stdin:

-
  exec:
    command: grep error
    stdin: '{{ steps[3].res.rawBody }}'
Test Runner: test using recorded values

The test runner is a built-in runner, so there is no need to specify it in the runners: section.

It evaluates the conditional expression using the recorded values.

-
  test: steps[3].res.status == 200
Dump Runner: dump recorded values

The dump runner is a built-in runner, so there is no need to specify it in the runners: section.

It dumps the specified recorded values.

-
  dump: steps[4].rows
Include Runner: include other runbook

The include runner is a built-in runner, so there is no need to specify it in the runners: section.

Include runner reads and runs the runbook in the specified path.

Recorded values are nested.

-
  include: path/to/get_token.yml
Bind Runner: bind variables

The bind runner is a built-in runner, so there is no need to specify it in the runners: section.

It bind runner binds any values with another key.

  -
    req:
      /users/k1low:
        get:
          body: null
  -
    bind:
      user_id: steps[0].res.body.data.id
  -
    dump: user_id

Install

As tool

deb:

Use dpkg-i-from-url

$ export RUNN_VERSION=X.X.X
$ curl -L https://git.io/dpkg-i-from-url | bash -s -- https://github.com/k1LoW/runn/releases/download/v$RUNN_VERSION/runn_$RUNN_VERSION-1_amd64.deb

RPM:

$ export RUNN_VERSION=X.X.X
$ yum install https://github.com/k1LoW/runn/releases/download/v$RUNN_VERSION/runn_$RUNN_VERSION-1_amd64.rpm

apk:

Use apk-add-from-url

$ export RUNN_VERSION=X.X.X
$ curl -L https://git.io/apk-add-from-url | sh -s -- https://github.com/k1LoW/runn/releases/download/v$RUNN_VERSION/runn_$RUNN_VERSION-1_amd64.apk

homebrew tap:

$ brew install k1LoW/tap/runn

manually:

Download binary from releases page

docker:

$ docker pull ghcr.io/k1low/runn:latest

go install:

$ go install github.com/k1LoW/runn/cmd/runn@latest
As test helper
$ go get github.com/k1LoW/runn

Alternatives

References

Documentation

Index

Constants

View Source
const (
	MediaTypeApplicationJSON           = "application/json"
	MediaTypeTextPlain                 = "text/plain"
	MediaTypeApplicationFormUrlencoded = "application/x-www-form-urlencoded"
)

Variables

View Source
var (
	T       = AsTestHelper
	Runbook = Book
)

Functions

func GetDesc added in v0.4.0

func GetDesc(opt Option) string

func Load added in v0.2.0

func Load(pathp string, opts ...Option) (*operators, error)

func LoadBook

func LoadBook(path string) (*book, error)

func New

func New(opts ...Option) (*operator, error)

func Paths added in v0.4.0

func Paths(pathp string) ([]string, error)

Types

type Option

type Option func(*book) error

func AsTestHelper

func AsTestHelper(t *testing.T) Option

func Book

func Book(path string) Option

func Books added in v0.4.0

func Books(pathp string) ([]Option, error)

func DBRunner

func DBRunner(name string, client *sql.DB) Option

func Debug added in v0.3.0

func Debug(debug bool) Option

func Desc

func Desc(desc string) Option

func FailFast added in v0.10.1

func FailFast(enable bool) Option

func HTTPRunner

func HTTPRunner(name, endpoint string, client *http.Client) Option

func HTTPRunnerWithHandler added in v0.6.0

func HTTPRunnerWithHandler(name string, h http.Handler) Option

func Interval added in v0.9.0

func Interval(d time.Duration) Option

func Runner

func Runner(name, dsn string) Option

func Var added in v0.4.0

func Var(k string, v interface{}) Option

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL