github.com/etecs-ru/gnomock@v0.13.2/options.go (about)

     1  package gnomock
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"io/ioutil"
     7  	"time"
     8  )
     9  
    10  const (
    11  	defaultTimeout             = time.Second * 300
    12  	defaultHealthcheckInterval = time.Millisecond * 250
    13  )
    14  
    15  // Option is an optional Gnomock configuration. Functions implementing this
    16  // signature may be combined to configure Gnomock containers for different use
    17  // cases
    18  type Option func(*Options)
    19  
    20  // WithContext sets the provided context to be used for setting up a Gnomock
    21  // container. Canceling this context will cause Start() to abort
    22  func WithContext(ctx context.Context) Option {
    23  	return func(o *Options) {
    24  		o.ctx = ctx
    25  	}
    26  }
    27  
    28  // WithInit lets the provided InitFunc to be called when a Gnomock container is
    29  // created, but before Start() returns. Use this function to run arbitrary code
    30  // on the new container before using it. It can be useful to bring the
    31  // container to a certain state (e.g create SQL schema)
    32  func WithInit(f InitFunc) Option {
    33  	return func(o *Options) {
    34  		o.init = f
    35  	}
    36  }
    37  
    38  // WithHealthCheck allows to define a rule to consider a Gnomock container
    39  // ready to use. For example, it can attempt to connect to this container, and
    40  // return an error on any failure, or nil on success. This function is called
    41  // repeatedly until the timeout is reached, or until a nil error is returned
    42  func WithHealthCheck(f HealthcheckFunc) Option {
    43  	return func(o *Options) {
    44  		o.healthcheck = f
    45  	}
    46  }
    47  
    48  // WithHealthCheckInterval defines an interval between two consecutive health
    49  // check calls. This is a constant interval
    50  func WithHealthCheckInterval(t time.Duration) Option {
    51  	return func(o *Options) {
    52  		o.healthcheckInterval = t
    53  	}
    54  }
    55  
    56  // WithTimeout sets the amount of time to wait for a created container to
    57  // become ready to use. All startup steps must complete before they time out:
    58  // start, wait until healthy, init.
    59  func WithTimeout(t time.Duration) Option {
    60  	return func(o *Options) {
    61  		o.Timeout = t
    62  	}
    63  }
    64  
    65  // WithEnv adds environment variable to the container. For example,
    66  // AWS_ACCESS_KEY_ID=FOOBARBAZ
    67  func WithEnv(env string) Option {
    68  	return func(o *Options) {
    69  		o.Env = append(o.Env, env)
    70  	}
    71  }
    72  
    73  // WithLogWriter sets the target where to write container logs. This can be
    74  // useful for debugging
    75  func WithLogWriter(w io.Writer) Option {
    76  	return func(o *Options) {
    77  		o.logWriter = w
    78  	}
    79  }
    80  
    81  // WithDebugMode allows Gnomock to output internal messages for debug purposes.
    82  // Containers created in debug mode will not be automatically removed on
    83  // failure to setup their initial state. Containers still might be removed if
    84  // they are shut down from the inside. Use WithLogWriter to see what happens
    85  // inside.
    86  func WithDebugMode() Option {
    87  	return func(o *Options) {
    88  		o.Debug = true
    89  	}
    90  }
    91  
    92  // WithContainerName allows to give a specific name to a new container. If a
    93  // container with the same name already exists, it is killed.
    94  func WithContainerName(name string) Option {
    95  	return func(o *Options) {
    96  		o.ContainerName = name
    97  	}
    98  }
    99  
   100  // WithPrivileged starts a container in privileged mode (like `docker run
   101  // --privileged`). This option should not be used unless you really need it.
   102  // One use case for this option would be to run a Preset that has some kind of
   103  // docker-in-docker functionality.
   104  func WithPrivileged() Option {
   105  	return func(o *Options) {
   106  		o.Privileged = true
   107  	}
   108  }
   109  
   110  // WithOptions allows to provide an existing set of Options instead of using
   111  // optional configuration.
   112  //
   113  // This way has its own limitations. For example, context or initialization
   114  // functions cannot be set in this way
   115  func WithOptions(options *Options) Option {
   116  	return func(o *Options) {
   117  		if options.Timeout > 0 {
   118  			o.Timeout = options.Timeout
   119  		}
   120  
   121  		o.Env = append(o.Env, options.Env...)
   122  		o.Debug = options.Debug
   123  		o.ContainerName = options.ContainerName
   124  	}
   125  }
   126  
   127  // WithCommand sets the command and its arguments to execute when container
   128  // first runs. This command replaces the command defined in docker image.
   129  func WithCommand(cmd string, args ...string) Option {
   130  	return func(o *Options) {
   131  		o.Cmd = append([]string{cmd}, args...)
   132  	}
   133  }
   134  
   135  // WithHostMounts allows to bind host path (`src`) inside the container under
   136  // `dst` path.
   137  func WithHostMounts(src, dst string) Option {
   138  	return func(o *Options) {
   139  		if o.HostMounts == nil {
   140  			o.HostMounts = make(map[string]string)
   141  		}
   142  
   143  		o.HostMounts[src] = dst
   144  	}
   145  }
   146  
   147  // WithDisableAutoCleanup disables auto-removal of this container when the
   148  // tests complete. Automatic cleanup is a safety net for tests that for some
   149  // reason fail to run `gnomock.Stop()` in the end, for example due to an
   150  // unexpected `os.Exit()` somewhere.
   151  func WithDisableAutoCleanup() Option {
   152  	return func(o *Options) {
   153  		o.DisableAutoCleanup = true
   154  	}
   155  }
   156  
   157  // HealthcheckFunc defines a function to be used to determine container health.
   158  // It receives a host and a port, and returns an error if the container is not
   159  // ready, or nil when the container can be used. One example of HealthcheckFunc
   160  // would be an attempt to establish the same connection to the container that
   161  // the application under test uses
   162  type HealthcheckFunc func(context.Context, *Container) error
   163  
   164  func nopHealthcheck(context.Context, *Container) error {
   165  	return nil
   166  }
   167  
   168  // InitFunc defines a function to be called on a ready to use container to set
   169  // up its initial state before running the tests. For example, InitFunc can
   170  // take care of creating a SQL table and inserting test data into it
   171  type InitFunc func(context.Context, *Container) error
   172  
   173  func nopInit(context.Context, *Container) error {
   174  	return nil
   175  }
   176  
   177  // Options includes Gnomock startup configuration. Functional options
   178  // (WithSomething) should be used instead of directly initializing objects of
   179  // this type whenever possible
   180  type Options struct {
   181  	// Timeout is an amount of time to wait before considering Start operation
   182  	// as failed.
   183  	Timeout time.Duration `json:"timeout"`
   184  
   185  	// Env is a list of environment variable to inject into the container. Each
   186  	// entry is in format ENV_VAR_NAME=value
   187  	Env []string `json:"env"`
   188  
   189  	// Debug flag allows Gnomock to be verbose about steps it takes
   190  	Debug bool `json:"debug"`
   191  
   192  	// Privileged starts a container in privileged mode.
   193  	Privileged bool `json:"privileged"`
   194  
   195  	// ContainerName allows to use a specific name for a new container. In case
   196  	// a container with the same name already exists, Gnomock kills it.
   197  	ContainerName string `json:"container_name"`
   198  
   199  	// Cmd is an optional command with its arguments to execute on container
   200  	// startup. This command replaces the default one set on docker image
   201  	// level.
   202  	Cmd []string `json:"cmd"`
   203  
   204  	// HostMounts allows to mount local paths into the container.
   205  	HostMounts map[string]string `json:"host_mounts"`
   206  
   207  	// DisableAutoCleanup prevents the container from being automatically
   208  	// stopped and removed after the tests are complete. By default, Gnomock
   209  	// will try to stop containers created by it right after the tests exit.
   210  	DisableAutoCleanup bool `json:"disable_cleanup"`
   211  
   212  	ctx                 context.Context
   213  	init                InitFunc
   214  	healthcheck         HealthcheckFunc
   215  	healthcheckInterval time.Duration
   216  	logWriter           io.Writer
   217  }
   218  
   219  func buildConfig(opts ...Option) *Options {
   220  	config := &Options{
   221  		ctx:                 context.Background(),
   222  		init:                nopInit,
   223  		healthcheck:         nopHealthcheck,
   224  		healthcheckInterval: defaultHealthcheckInterval,
   225  		Timeout:             defaultTimeout,
   226  		logWriter:           ioutil.Discard,
   227  	}
   228  
   229  	for _, opt := range opts {
   230  		opt(config)
   231  	}
   232  
   233  	return config
   234  }