Documentation ¶
Overview ¶
Package hivesim is a Go wrapper for the Hive Simulation API. You can use this package to write simulations for Hive in Go.
The hivesim API wrapper contains a few components that are important for interacting with the hive simulation API:
- test suites
- test cases
- client(s)
- networks (if the simulation calls for a more complex network topology
Test Suites and Test Cases ¶
A test suite represents a single run of a simulator. A test suite can contain several test cases. Test cases represent an individual test against one or more clients.
In order to execute a test against a client, it is necessary to create a test suite first and add one or more test cases to that suite. This can be done by creating `Suite` object, as such:
suite := hivesim.Suite{ Name: "MyTest", Description: "This simulation test does XYZ.", }
The `Suite` has an additional field, `Tests`, which represents all the test cases to be executed by the test suite. Test cases can be added to the suite using the `Add()` method.
A test case can be represented in either of the following formats:
// TestSpec is the description of a test. Using this test type doesn't launch any clients by default. // To interact with clients, you can launch them using the t.Client method: // // c := t.Client() // c.RPC().Call(...) // // or run a subtest using t.RunClientTest(): // // t.RunClientTest(hivesim.ClientTestSpec{...}) // type TestSpec struct { Name string Description string Run func(*T) // this is the function that will be executed by the test suite } // ClientTestSpec is a test against a single client. You can either put this in your suite // directly, or launch it using RunClient or RunAllClients from another test. // // When used as a test in a suite, the test runs against all available client types. // // If the Name of the test includes "CLIENT", it is replaced by the client name being tested. type ClientTestSpec struct { Name string Description string Parameters Params Files map[string]string Run func(*T, *Client) // this is the function that will be executed by the test suite }
It is also possible to add a test case to the test suite without using the two above structs, so long as it implements the following interface:
type AnyTest interface { runTest(*Simulation, SuiteID) error }
Creating a Test Run ¶
A test run can make use of the resources granted to it by the `T` object at runtime. `T` represents a running test and behaves a lot like testing.T, but has some additional methods for launching clients.
type T struct { Sim *Simulation TestID TestID SuiteID SuiteID mu sync.Mutex result TestResult }
The `T` object can start a client using the `StartClient()` method. `StartClient()` returns an object `Client` with information about the client container. `Client` also offers two methods: `EnodeURL()`, which returns the enode URL of the client, and `RPC()`, which returns an RPC client connected to the client's RPC server.
`T` can also run a test against a client using any of the `Run__()` methods. It can also pipe logs and test failures through to the simulation log file, among other methods.
The `Sim` field (which is a pointer to an instance of `Simulation`) in the `T` object is especially useful as it provides several methods for communicating with the hive simulation API, such as:
- starting / ending test suites and tests
- starting / stopping / getting information about a client
- creating / removing networks
- connecting / disconnecting containers to/from a network
- getting the IP address of a container on a specific network
Running a Test Suite ¶
It is possible to call either `RunSuite()` or `MustRunSuite()` on the `Suite`, the only difference being the error handling.
`RunSuite()` will run all tests in the `Suite`, returning an error upon failure. `MustRunSuite()` will run all tests in the `Suite`, exiting the process if there is a problem executing a test.
Both functions take a pointer to an instance of `Simulation` as well as a `Suite`.
To get an instance of `Simulation`, call the constructor function `New()`. This will look up the hive host server URI and return an instance of `Simulation` that will be able to access the running hive host server.
Index ¶
- Variables
- func MustRun(host *Simulation, suites ...Suite)
- func MustRunSuite(host *Simulation, suite Suite)
- func NewDocsCollector() *docsCollector
- func Run(host *Simulation, suites ...Suite) error
- func RunSuite(host *Simulation, suite Suite) error
- type AnyTest
- type Client
- func (c *Client) EngineAPI() *rpc.Client
- func (c *Client) EnodeURL() (string, error)
- func (c *Client) EnodeURLNetwork(network string) (string, error)
- func (c *Client) Exec(command ...string) (*ExecInfo, error)
- func (c *Client) Pause() error
- func (c *Client) RPC() *rpc.Client
- func (c *Client) Unpause() error
- type ClientDefinition
- type ClientMetadata
- type ClientTestSpec
- type ExecInfo
- type FileWriter
- type Params
- type Simulation
- func (sim *Simulation) ClientEnodeURL(testSuite SuiteID, test TestID, node string) (string, error)
- func (sim *Simulation) ClientEnodeURLNetwork(testSuite SuiteID, test TestID, node string, network string) (string, error)
- func (sim *Simulation) ClientExec(testSuite SuiteID, test TestID, nodeid string, cmd []string) (*ExecInfo, error)
- func (sim *Simulation) ClientTypes() ([]*ClientDefinition, error)
- func (sim *Simulation) CollectTestsOnly() bool
- func (sim *Simulation) ConnectContainer(testSuite SuiteID, network, containerID string) error
- func (sim *Simulation) ContainerNetworkIP(testSuite SuiteID, network, containerID string) (string, error)
- func (sim *Simulation) CreateNetwork(testSuite SuiteID, networkName string) error
- func (sim *Simulation) DisconnectContainer(testSuite SuiteID, network, containerID string) error
- func (sim *Simulation) EndSuite(testSuite SuiteID) error
- func (sim *Simulation) EndTest(testSuite SuiteID, test TestID, testResult TestResult) error
- func (sim *Simulation) PauseClient(testSuite SuiteID, test TestID, nodeid string) error
- func (sim *Simulation) RemoveNetwork(testSuite SuiteID, network string) error
- func (sim *Simulation) SetTestPattern(p string)
- func (sim *Simulation) StartClient(testSuite SuiteID, test TestID, parameters map[string]string, ...) (string, net.IP, error)
- func (sim *Simulation) StartClientWithOptions(testSuite SuiteID, test TestID, clientType string, options ...StartOption) (string, net.IP, error)
- func (sim *Simulation) StartSuite(suite *simapi.TestRequest, simlog string) (SuiteID, error)
- func (sim *Simulation) StartTest(testSuite SuiteID, test *simapi.TestRequest) (TestID, error)
- func (sim *Simulation) StopClient(testSuite SuiteID, test TestID, nodeid string) error
- func (sim *Simulation) TestPattern() (suiteExpr string, testNameExpr string)
- func (sim *Simulation) UnpauseClient(testSuite SuiteID, test TestID, nodeid string) error
- type StartOption
- type Suite
- type SuiteID
- type T
- func (t *T) Error(values ...interface{})
- func (t *T) Errorf(format string, values ...interface{})
- func (t *T) Fail()
- func (t *T) FailNow()
- func (t *T) Failed() bool
- func (t *T) Fatal(values ...interface{})
- func (t *T) Fatalf(format string, values ...interface{})
- func (t *T) Log(values ...interface{})
- func (t *T) Logf(format string, values ...interface{})
- func (t *T) Run(spec TestSpec)
- func (t *T) RunAllClients(spec ClientTestSpec)
- func (t *T) RunClient(clientType string, spec ClientTestSpec)
- func (t *T) StartClient(clientType string, option ...StartOption) *Client
- type TestID
- type TestResult
- type TestSpec
Constants ¶
This section is empty.
Variables ¶
var ENGINEAPI_JWT_SECRET = [32]byte{0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x65}
This is the static secret configured for all execution-layer clients.
Functions ¶
func MustRun ¶
func MustRun(host *Simulation, suites ...Suite)
MustRun executes all given test suites, exiting the process if there is a problem reaching the simulation API.
func MustRunSuite ¶
func MustRunSuite(host *Simulation, suite Suite)
MustRunSuite runs the given suite, exiting the process if there is a problem reaching the simulation API.
func NewDocsCollector ¶
func NewDocsCollector() *docsCollector
NewDocsCollector creates a new docs collector object. Tries to parse the simulator name and also the output directory from the environment variables.
func RunSuite ¶
func RunSuite(host *Simulation, suite Suite) error
RunSuite runs all tests in a suite.
Types ¶
type AnyTest ¶
type AnyTest interface {
// contains filtered or unexported methods
}
AnyTest is a TestSpec or ClientTestSpec.
type Client ¶
type Client struct { Type string Container string IP net.IP // contains filtered or unexported fields }
Client represents a running client.
func (*Client) EngineAPI ¶
EngineAPI returns an RPC client connected to an execution-layer client's engine API server.
func (*Client) EnodeURLNetwork ¶
EnodeURL returns the peer-to-peer endpoint of the client on a specific network.
type ClientDefinition ¶
type ClientDefinition struct { Name string `json:"name"` Version string `json:"version"` Meta ClientMetadata `json:"meta"` }
ClientDefinition is served by the /clients API endpoint to list the available clients
func (*ClientDefinition) HasRole ¶
func (m *ClientDefinition) HasRole(role string) bool
HasRole reports whether the client has the given role.
type ClientMetadata ¶
type ClientMetadata struct {
Roles []string `yaml:"roles" json:"roles"`
}
ClientMetadata is part of the ClientDefinition and lists metadata
type ClientTestSpec ¶
type ClientTestSpec struct { // These fields are displayed in the UI. Be sure to add // a meaningful description here. Name string // Name is the unique identifier for the test [Mandatory] DisplayName string // Display name for the test (Name will be used if unset) [Optional] Description string // Description of the test (if empty, test won't appear in documentation) [Optional] Category string // Category of the test [Optional] // If AlwaysRun is true, the test will run even if Name does not match the test // pattern. This option is useful for tests that launch a client instance and // then perform further tests against it. AlwaysRun bool // This filters client types by role. // If no role is specified, the test runs for all available client types. Role string // Parameters and Files are launch options for client instances. Parameters Params Files map[string]string // The Run function is invoked when the test executes. Run func(*T, *Client) }
ClientTestSpec is a test against a single client. You can either put this in your suite directly, or launch it using RunClient or RunAllClients from another test.
When used as a test in a suite, the test runs against all available client types, with the specified Role. If no Role is specified, the test runs with all available clients.
If the Name of the test includes "CLIENT", it is replaced by the client name being tested.
type ExecInfo ¶
type ExecInfo struct { Stdout string `json:"stdout"` Stderr string `json:"stderr"` ExitCode int `json:"exitCode"` }
ExecInfo is the result of running a command in a client container.
type FileWriter ¶
type FileWriter interface {
CreateWriter(path string) (io.WriteCloser, error)
}
FileWriter interface. Used to create the markdown files.
func NewFileWriter ¶
func NewFileWriter(basePath string) FileWriter
NewFileWriter creates a new file writer with the given base path.
type Params ¶
Params contains client launch parameters. This exists because tests usually want to define common parameters as a global variable and then customize them for specific clients.
type Simulation ¶
type Simulation struct {
// contains filtered or unexported fields
}
Simulation wraps the simulation HTTP API provided by hive.
func New ¶
func New() *Simulation
New looks up the hive host URI using the HIVE_SIMULATOR environment variable and connects to it. It will panic if HIVE_SIMULATOR is not set. If HIVE_DOCS_MODE is set to "true", it will inhibit most of the functionality in order to simplify execution for documentation generation.
func NewAt ¶
func NewAt(url string) *Simulation
NewAt creates a simulation connected to the given API endpoint. You'll will rarely need to use this. In simulations launched by hive, use New() instead.
func (*Simulation) ClientEnodeURL ¶
ClientEnodeURL returns the enode URL of a running client.
func (*Simulation) ClientEnodeURLNetwork ¶
func (sim *Simulation) ClientEnodeURLNetwork(testSuite SuiteID, test TestID, node string, network string) (string, error)
ClientEnodeURLCustomNetwork returns the enode URL of a running client in a custom network.
func (*Simulation) ClientExec ¶
func (sim *Simulation) ClientExec(testSuite SuiteID, test TestID, nodeid string, cmd []string) (*ExecInfo, error)
ClientExec runs a command in a running client.
func (*Simulation) ClientTypes ¶
func (sim *Simulation) ClientTypes() ([]*ClientDefinition, error)
ClientTypes returns all client types available to this simulator run. This depends on both the available client set and the command line filters.
func (*Simulation) CollectTestsOnly ¶
func (sim *Simulation) CollectTestsOnly() bool
CollectTestsOnly returns true if the simulation is running in collect-tests-only mode.
func (*Simulation) ConnectContainer ¶
func (sim *Simulation) ConnectContainer(testSuite SuiteID, network, containerID string) error
ConnectContainer sends a request to the hive server to connect the given container to the given network.
func (*Simulation) ContainerNetworkIP ¶
func (sim *Simulation) ContainerNetworkIP(testSuite SuiteID, network, containerID string) (string, error)
ContainerNetworkIP returns the IP address of a container on the given network. If the container ID is "simulation", it returns the IP address of the simulator container.
func (*Simulation) CreateNetwork ¶
func (sim *Simulation) CreateNetwork(testSuite SuiteID, networkName string) error
CreateNetwork sends a request to the hive server to create a docker network by the given name.
func (*Simulation) DisconnectContainer ¶
func (sim *Simulation) DisconnectContainer(testSuite SuiteID, network, containerID string) error
DisconnectContainer sends a request to the hive server to disconnect the given container from the given network.
func (*Simulation) EndSuite ¶
func (sim *Simulation) EndSuite(testSuite SuiteID) error
EndSuite signals the end of a test suite.
func (*Simulation) EndTest ¶
func (sim *Simulation) EndTest(testSuite SuiteID, test TestID, testResult TestResult) error
EndTest finishes the test case, cleaning up everything, logging results, and returning an error if the process could not be completed.
func (*Simulation) PauseClient ¶
func (sim *Simulation) PauseClient(testSuite SuiteID, test TestID, nodeid string) error
PauseClient signals to the host that the node needs to be paused.
func (*Simulation) RemoveNetwork ¶
func (sim *Simulation) RemoveNetwork(testSuite SuiteID, network string) error
RemoveNetwork sends a request to the hive server to remove the given network.
func (*Simulation) SetTestPattern ¶
func (sim *Simulation) SetTestPattern(p string)
SetTestPattern sets the regular expression that enables/skips suites and test cases. This method is provided for use in unit tests. For simulator runs launched by hive, the test pattern is set automatically in New().
func (*Simulation) StartClient ¶
func (sim *Simulation) StartClient(testSuite SuiteID, test TestID, parameters map[string]string, initFiles map[string]string) (string, net.IP, error)
StartClient starts a new node (or other container) with the specified parameters. One parameter must be named CLIENT and should contain one of the client types from GetClientTypes. The input is used as environment variables in the new container. Returns container id and ip.
func (*Simulation) StartClientWithOptions ¶
func (sim *Simulation) StartClientWithOptions(testSuite SuiteID, test TestID, clientType string, options ...StartOption) (string, net.IP, error)
StartClientWithOptions starts a new node (or other container) with specified options. Returns container id and ip.
func (*Simulation) StartSuite ¶
func (sim *Simulation) StartSuite(suite *simapi.TestRequest, simlog string) (SuiteID, error)
StartSuite signals the start of a test suite.
func (*Simulation) StartTest ¶
func (sim *Simulation) StartTest(testSuite SuiteID, test *simapi.TestRequest) (TestID, error)
StartTest starts a new test case, returning the testcase id as a context identifier.
func (*Simulation) StopClient ¶
func (sim *Simulation) StopClient(testSuite SuiteID, test TestID, nodeid string) error
StopClient signals to the host that the node is no longer required.
func (*Simulation) TestPattern ¶
func (sim *Simulation) TestPattern() (suiteExpr string, testNameExpr string)
TestPattern returns the regular expressions used to enable/skip suite and test names.
func (*Simulation) UnpauseClient ¶
func (sim *Simulation) UnpauseClient(testSuite SuiteID, test TestID, nodeid string) error
UnpauseClient signals to the host that the node needs to be unpaused.
type StartOption ¶
type StartOption interface {
// contains filtered or unexported methods
}
StartOption is a parameter for starting a client.
func Bundle ¶
func Bundle(option ...StartOption) StartOption
Bundle combines start options, e.g. to bundle files together as option.
func WithDynamicFile ¶
func WithDynamicFile(dstPath string, src func() (io.ReadCloser, error)) StartOption
WithDynamicFile adds a file to a client, sourced dynamically from the given src function, called upon usage of the returned StartOption.
A StartOption, and thus the src function, should be reusable and safe to use in parallel. Dynamic files can override static file sources (see WithStaticFiles) and vice-versa.
func WithInitialNetworks ¶
func WithInitialNetworks(networks []string) StartOption
WithInitialNetworks configures networks that the client is initially connected to.
func WithStaticFiles ¶
func WithStaticFiles(initFiles map[string]string) StartOption
WithStaticFiles adds files from the local filesystem to the client. Map: destination file path -> source file path.
type Suite ¶
type Suite struct { Name string // Name is the unique identifier for the suite [Mandatory] DisplayName string // Display name for the suite (Name will be used if unset) [Optional] Location string // Documentation output location for the test suite [Optional] Category string // Category of the test suite [Optional] Description string // Description of the test suite (if empty, suite won't appear in documentation) [Optional] Tests []AnyTest }
Suite is the description of a test suite.
type T ¶
type T struct { // Test case info. Sim *Simulation TestID TestID SuiteID SuiteID // contains filtered or unexported fields }
T is a running test. This is a lot like testing.T, but has some additional methods for launching clients.
All test log output (via t.Log, t.Logf) goes to the 'details' section of the test report.
func (*T) FailNow ¶
func (t *T) FailNow()
FailNow signals that the test has failed and exits the test immediately. As with testing.T.FailNow(), this should only be called from the main test goroutine.
func (*T) Fatal ¶
func (t *T) Fatal(values ...interface{})
Fatal is like testing.T.Fatal. It fails the test immediately.
func (*T) Log ¶
func (t *T) Log(values ...interface{})
Log prints to standard output, which goes to the simulation log file.
func (*T) Run ¶
Run runs a subtest of this test. It waits for the subtest to complete before continuing. It is safe to call this from multiple goroutines concurrently, just be sure to wait for all your tests to finish until returning from the parent test.
func (*T) RunAllClients ¶
func (t *T) RunAllClients(spec ClientTestSpec)
RunAllClients runs the given client test against all available client types. It waits for all subtests to complete.
func (*T) RunClient ¶
func (t *T) RunClient(clientType string, spec ClientTestSpec)
RunClient runs the given client test against a single client type. It waits for the subtest to complete.
func (*T) StartClient ¶
func (t *T) StartClient(clientType string, option ...StartOption) *Client
StartClient starts a client instance. If the client cannot by started, the test fails immediately.
type TestResult ¶
TestResult describes the outcome of a test.
type TestSpec ¶
type TestSpec struct { // These fields are displayed in the UI. Be sure to add // a meaningful description here. Name string // Name is the unique identifier for the test [Mandatory] DisplayName string // Display name for the test (Name will be used if unset) [Optional] Description string // Description of the test (if empty, test won't appear in documentation) [Optional] Category string // Category of the test [Optional] // If AlwaysRun is true, the test will run even if Name does not match the test // pattern. This option is useful for tests that launch a client instance and // then perform further tests against it. AlwaysRun bool // The Run function is invoked when the test executes. Run func(*T) }
TestSpec is the description of a test.
Using this test type doesn't launch any clients by default. To interact with clients, you can launch them using the t.Client method:
c := t.Client() c.RPC().Call(...)
or run a subtest using t.RunClientTest():
t.RunClientTest(hivesim.ClientTestSpec{...})