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 }