mlabtest

package module
v0.0.0-...-0391e5f Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2017 License: MIT Imports: 15 Imported by: 0

README

Integrate MinuteLab labs into go "Unit" tests

godoc reference Build Status

Support for integrating MinuteLab labs inside go "unit" testing.

Introduction

Write "unit" tests that can set up servers on demand to run for the duration of the test.

Suppose you have a code that interact with servers in its environment (database, Hadoop, Redis, Spark etc.) Normally if you want to test the interaction with the environment you would have to specify that the "unit testing" would be done in an environment that contain the right database. This specification would mostly take the form of instructions to developers of the expected environment, and encoded in some form into the continuous integration framework.

MinuteLab allows a different approach: the test code itself start on-demand the required environment.

  • Different branches can have different environment requirements. This will be completely transparent to who ever run the unit tests (developers or CI system), since they will just run go test, and the needed environment will be set up on demand.

  • Different tests on the same branch can use different environment, and it will be transparent to who ever happen to run the test.

  • Minute Lab environment can include several servers, with private networking between them, and the testing environment. Normally "unit testing" is limited to whatever can be easily installed on one machine (either a developer desktop, or a cloud CI container). Minute Lab break this barrier and allow testing with environment containing clusters of servers

Usage

The main way to use the the integration with the code testing is something like

func TestSomething(t *testing.T) {}
  lab,_ := mlabtest.NewStart(t, "script.mlab","arg1","arg2")
  defer lab.Close()
}

This will cause the lab to startwhen the test start, and be cleaned up at the end.

If one need a lab that start for a whole pacakge it can be started in the TestMain method:

func TestMain(m *testing.M) {
    lab,err := mlabtest.NewStart(t, "script.mlab","arg1","arg2")
    if err!=nil {
        return log.Fatal("Failed starting lab: ",err)
    }
    defer lab.Close()
	os.Exit(m.Run())
}
Examples

This repository contain two examples, that are both useful on their own we use them internally in Minute Lab), and show how to use the base functionality to create easy testing for specific environments.

Postgres example

the pgtest sub-package show how mlab tests can be used to test code interacting with PostgreSQL.

When creating a new pgtest.Postgres object it start a database, and then the GetDB method can be used to get a normal *sql.DB which can be used with the normal go function

func TestPostgress(t *testing.T) {
	pg, _ := New(t, "", nil)
	defer pg.Close()

	db, err := pg.GetDB("")
	if err != nil {
		t.Fatal("Failed creating db object:", err)
	}

	defer db.Close()

	if err := db.Ping(); err != nil {
		t.Fatal("Failed pinging databse:", err)
	}
}
Postgres + Sqitch example

The sqitchdb sub-package go one step forward. It not only manage the database itself, but also uses the Sqitch tool to manage the schema. When this object is created, it start a database, load a schema using the sqitch tool (that does not to be installed because it is running in its own container), and give back a go *sql.DB object ready for testing.

func TestSqitch(t *testing.T) {
	dbLab, _ := New(t, "scheme", "", nil)
	defer dbLab.Close()

    db:=dblab.Conn()
    rows,err:=db.Query("SELECT * FROM users")
    if err!=nil {
        t.Errorf("Failed selecting from database: %s",err)
    }
}

Documentation

Overview

Package mlabtest is used to run unit tests that set up a whole lab

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetSourceDir

func GetSourceDir(i interface{}) (string, error)

GetSourceDir return the path in the source where the type is defined.

Note: We need to have the sources (in the correct GOPATH) for this to work

Useful for loading test resources from the source directory of a library in test that use that library

func NeedForwarding

func NeedForwarding() bool

NeedForwarding return true if the labs need to be accessed at 127.0.0.1 with the mapped ports otherwise they can be accessed at their own address with the original port

func NewLineLogger

func NewLineLogger(f LogFunc) io.WriteCloser

NewLineLogger allow to log lines of output produced by MLab containers It create an io.WriteCloser that parses the output into line and send them to the specified function.

Types

type LogFunc

type LogFunc func(string)

LogFunc is a type of function used to log lines of output

func DefaultLogger

func DefaultLogger(tb testing.TB, prefix string, logger LogFunc) LogFunc

DefaultLogger create a "default" logging function If one is givven it is used as is, If not one is built, with the testing object if given, and with stdout otherwize

type MLab

type MLab struct {

	// if logger is set it would be called to log "internal" MLab events
	Logger func(string)
	// if Stdin is not nill it is connected to the mlab
	// otherwise it is connected to the null device.
	// Must be set before calling Start
	Stdin io.Reader
	// id Stdout and/or Stderr are not nill they are connected to the mlab
	// (stdout is not connected directly)
	Stdout io.Writer
	Stderr io.Writer
	// contains filtered or unexported fields
}

MLab represent a running minutelab

After creating the lab object, and possibly setting other paramters, the lab is started with the Start method.

The lab should be closed with the Close method (even if it was only created or if start return an error) The lab should be built such that when it is ready it will detach

func New

func New(tb testing.TB, script string, args ...string) (*MLab, error)

New create (but does not start) a new mlab with the specified arguments The lab can be optionally associated with a testing framework object (like *testing.T), if it does it behave in a way more suitable for unit testing:

  1. Both New and Start won't return errors, instead the would abort the test using Fatal, so testing code does not need to explicitly check for errors
  2. It will send logs about lab setup through the testing log function

func NewStart

func NewStart(tb testing.TB, script string, args ...string) (*MLab, error)

NewStart create a new lab and start it immediatly if tb is not nil testing code can assume that the function succeed and not test for errors

func (*MLab) Close

func (m *MLab) Close() error

Close kills the mlab if neccesary and clean after it

func (*MLab) GetAddressPort

func (m *MLab) GetAddressPort(port int) (net.IP, int, error)

GetAddressPort return the address and port to be used to access the specified internal port

func (*MLab) IsClosed

func (m *MLab) IsClosed() bool

IsClosed true if the command is closed

func (*MLab) Log

func (m *MLab) Log(format string, a ...interface{})

Log a line to the mlab configured logger

func (*MLab) NetConfig

func (m *MLab) NetConfig() (*NetConfig, error)

NetConfig get the network configuration of a running container result is cached, so future calls are fast

func (*MLab) Start

func (m *MLab) Start() error

Start the lab

func (*MLab) Wait

func (m *MLab) Wait()

Wait until the lab died (or start failed to start it)

type NetConfig

type NetConfig struct {
	Interfaces   map[string]net.IP
	ExposedPorts map[int]int
}

NetConfig is the network configuration of a lab

func (*NetConfig) IP

func (n *NetConfig) IP() net.IP

IP get the main IP of the lab

Directories

Path Synopsis
Package sqitchdb allow "unit testing" of (postgres) database whose schema is controlled by sqitch Calling New will start a container running postgres with the latest schema/data loaded.
Package sqitchdb allow "unit testing" of (postgres) database whose schema is controlled by sqitch Calling New will start a container running postgres with the latest schema/data loaded.

Jump to

Keyboard shortcuts

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