tester

package module
v0.0.0-...-8939947 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2022 License: MIT Imports: 3 Imported by: 0

README

* tester

-----

*NOTE*
I'm no longer working on nanzhong/tester. Instead I've taken the learnings from this project and running it for various use cases and adopted them into a new version of a test orchestration platform. It's still a work-in-progress and does not have feature parity with nanzhong/tester (but also has many new and different features). Feel free to follow along at [[https://github.com/nanzhong/tstr][nanzhong/tstr]].

-----

Convenient tooling for scheduling, running, and reporting on go tests.

[[https://github.com/nanzhong/tester][nanzhong/tester]] is not a testing framework, and it does not impose any patterns on how tests are written. It is a tool that makes it easy to schedule test runs and to collect their results. A common use case for it is to manage a suite of end to end tests, to visualize the test results, and to alert on failures.

** Demo
[[screenshot.jpg]]
A live example of the latest version of this tooling can be found at https://tester.nanzho.ng.

** How it works
[[https://github.com/nanzhong/tester][nanzhong/tester]] is made up of three parts: the server, the runner, and the configuration.

*** Server
The server provides the bulk of the functionality. It is responsible for:
- configuration of tests
- scheduling test runs
- serving the HTTP user interface 
- providing the HTTP based API that the runners use
- alerting on test failures

All the test run data is stored in a postgresql database.

*** Runner
The runner is responsible for running the tests themselves. It coordinates what tests to run by interacting with the API provided by the server.

The only configuration needed by a runner by default is what is required to communicate with the server. It can retrieve test configuration and binaries from the server or run tests using existing test binaries available in its environment.

*** Configuration
A common configuration format is shared between the server and runners. 

The server uses the configuration to:
- determine what tests to schedule
- determine how it alerts
- configuring the optional slack integration
  - generating the help information for the custom slack command

The runners use the configuration to:
- let the server know what tests they are capable of running and requesting runs

Format:
#+BEGIN_SRC js
{
  "packages": [
    {
      // name of test package
      "name": "pkg",
      // path to the test binary for the package
      "path": "/opt/tester/bin/pkg.test",
      // test binary options that are supported      
      "options": [
        {
          "name": "test.timeout",
          "description": "Maximum time tests can run for",
          "default": "1m"
        }
      ]
    },
    // ...
  ],
  "scheduler": {
    // how long a test is allowed to run before timing out
    "run_timeout": "1m"
  },
  "slack": {
    // the default channels all failures should be alerted on
    "default_channels": [ "alerts" ],
    "custom_channels": {
      // additional custom channels that package failures to should be alerted on
      "pkg": [ "pkg-alerts" ]
    }
  }
}
#+END_SRC

An full example of the configuration format can be found in [[config.json][config.json]] that is used for the live demo.

** Usage
[[https://github.com/nanzhong/tester][nanzhong/tester]] builds into a single ~tester~ binary that has subcommands for running the server (~tester serve~) and runner (~tester run~).

#+BEGIN_SRC sh
~ go get github.com/nanzhong/tester/cmd/tester
~ tester --help
#+END_SRC

Each commit is automatically built into a container image that contains the `tester` binary, and it is published to docker hub. You can find the set of images at [[https://hub.docker.com/repository/docker/nanzhong/tester][https://hub.docker.com/repository/docker/nanzhong/tester]].

*** Server
The server can be started with

#+BEGIN_SRC sh
~ tester serve \
  --addr 127.0.0.1:8080                    `# address the listen on` \
  --api-key secret-key                     `# symmetric key for API auth ` \
  --config ./path/to/config                `# path to configuration file` \
  --pg-dsn postgresql://user:pass@host/db  `# postgresql dsn for storing results`
#+END_SRC

**** Slack integration
There are two slack integrations that are supported. The first is alerting in slack channels on failed test runs, the second is setting up a custom slack command that can be used to trigger test runs.

Both of these require creating and setting up a slack application and the configuring the following server flags:
#+BEGIN_SRC sh
--slack-access-token string    `# Slack app access token` \
--slack-signing-secret string  `# Slack signing secret`
#+END_SRC

**** Okta authentication
If the reporting UI requires authentication, okta oauth is supported.

These additional server flags need to be configured:
#+BEGIN_SRC sh
--okta-client-id string      `# Okta client ID` \
--okta-client-secret string  `# Okta client secret` \
--okta-issuer string         `# Okta issuer` \
--okta-redirect-uri string   `# Okta redirect URI` \
--okta-session-key string    `# Okta session key`
#+END_SRC

*** Runner
A runner can be started with

#+BEGIN_SRC sh
~ tester run \
  --tester-addr http://127.0.0.18080  `# address where the tester server is listening` \
  --api-key secret-key                `# symmetric key for API auth ` \
  --test-bins-path /path/to/bins      `# path test binaries are expected to be at and downloaded to` \
  --local-test-bins-only              `# wheter or not to disable downloading test binaries from the server` \
  --packages-include pkg1,pkg2        `# list of package to consider when claiming runs from the server` \
  --packages-exclude pkg1,pkg2        `# list of package to exclude when claiming runs from the server (has priority over include list)` 
#+END_SRC

/Note/ that multiple runner can be used to increase throughput.

** Next Steps
There's some strong irony here that the test tooling isn't well tested.

[[https://github.com/nanzhong/tester][nanzhong/tester]] started as part of a hackathon project and as a result a lot of tradeoffs where made. The general direction and approach has shifted a number of times and adding better test coverage in a time of flux was not a priority. Having said that, direction and approach are much more stable now, and improving test coverage and stability is now a priority.

There's still quite a lot to do before a first /"official release"/ and the following are the priorities
- [ ] improve test coverage
- [ ] cleanup runner implementation (eg. abstract out parsing test output from the running of the tests)
- [ ] export prometheus metrics

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option struct {
	Name        string `json:"name"`
	Value       string `json:"value"`
	Description string `json:"description"`
	Default     string `json:"default"`
}

Option represents an option for how a package can be run.

func (*Option) String

func (o *Option) String() string

String returns a string representation of the option.

type Package

type Package struct {
	Name      string        `json:"name"`
	Path      string        `json:"path"`
	SHA256Sum string        `json:"sha256sum"`
	RunDelay  time.Duration `json:"run_delay"`
	Options   []Option      `json:"options"`
}

Package represents a go package that can be tested or benchmarked.

type PackageSummary

type PackageSummary struct {
	Package      string
	RunIDs       []uuid.UUID
	ErrorRunIDs  []uuid.UUID
	PassedTests  map[string][]uuid.UUID
	FailedTests  map[string][]uuid.UUID
	SkippedTests map[string][]uuid.UUID
}

func (*PackageSummary) NumFailedTests

func (s *PackageSummary) NumFailedTests() int

func (*PackageSummary) NumPassedTests

func (s *PackageSummary) NumPassedTests() int

func (*PackageSummary) NumSkippedTests

func (s *PackageSummary) NumSkippedTests() int

func (*PackageSummary) NumTotalTests

func (s *PackageSummary) NumTotalTests() int

func (*PackageSummary) PercentFailedTests

func (s *PackageSummary) PercentFailedTests() float64

func (*PackageSummary) PercentPassedTests

func (s *PackageSummary) PercentPassedTests() float64

func (*PackageSummary) PercentSkippedTests

func (s *PackageSummary) PercentSkippedTests() float64

type Run

type Run struct {
	ID         uuid.UUID `json:"id"`
	Package    string    `json:"package"`
	Args       []string  `json:"args"`
	Meta       RunMeta   `json:"meta"`
	EnqueuedAt time.Time `json:"enqueued_at"`
	StartedAt  time.Time `json:"started_at"`
	FinishedAt time.Time `json:"finished_at"`
	Tests      []*Test   `json:"tests"`
	Error      string    `json:"error"`
}

Run is the representation of a pending test or benchmark that has not completed.

func (*Run) Duration

func (r *Run) Duration() time.Duration

type RunMeta

type RunMeta struct {
	Runner string `json:"runner"`
}

RunMeta is additional metadata associated with the run.

type RunSummary

type RunSummary struct {
	Time           time.Time
	Duration       time.Duration
	PackageSummary map[string]*PackageSummary
}

func (*RunSummary) NumErrorRuns

func (s *RunSummary) NumErrorRuns() int

func (*RunSummary) NumFailedTests

func (s *RunSummary) NumFailedTests() int

func (*RunSummary) NumPassedTests

func (s *RunSummary) NumPassedTests() int

func (*RunSummary) NumRuns

func (s *RunSummary) NumRuns() int

func (*RunSummary) NumSkippedTests

func (s *RunSummary) NumSkippedTests() int

func (*RunSummary) NumTotalTests

func (s *RunSummary) NumTotalTests() int

func (*RunSummary) PercentFailedTests

func (s *RunSummary) PercentFailedTests() float64

func (*RunSummary) PercentPassedTests

func (s *RunSummary) PercentPassedTests() float64

func (*RunSummary) PercentSkippedTests

func (s *RunSummary) PercentSkippedTests() float64

type T

type T struct {
	TB

	SubTs []*T `json:"sub_ts"`
}

T represents the results of a `testing.T`.

type TB

type TB struct {
	Name       string    `json:"name"`
	StartedAt  time.Time `json:"started_at"`
	FinishedAt time.Time `json:"finished_at"`
	State      TBState   `json:"state"`
}

TB is the representation of the common fields of a testing.TB.

func (*TB) Duration

func (c *TB) Duration() time.Duration

Duration returns the run duration the Test.

type TBLog

type TBLog struct {
	Time   time.Time `json:"time"`
	Name   string    `json:"name"`
	Output []byte    `json:"output"`
}

type TBState

type TBState string

TBState represents the completion state of a `testing.TB`.

const (
	// TBStatePassed represents a passed test.
	TBStatePassed TBState = "passed"
	// TBFailed represents a failed test.
	TBStateFailed TBState = "failed"
	// TBSkipped represents a skipped test.
	TBStateSkipped TBState = "skipped"
)

type Test

type Test struct {
	ID      uuid.UUID `json:"id"`
	Package string    `json:"package"`
	RunID   uuid.UUID `json:"run_id"`

	Result *T      `json:"result"`
	Logs   []TBLog `json:"logs"`
}

Test is a run of a `testing.T`.

Directories

Path Synopsis
cmd
Package db is a generated GoMock package.
Package db is a generated GoMock package.

Jump to

Keyboard shortcuts

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