Initial QSfera import
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
// TerminateOptions is a type that holds the options for terminating a container.
|
||||
type TerminateOptions struct {
|
||||
ctx context.Context
|
||||
stopTimeout *time.Duration
|
||||
volumes []string
|
||||
}
|
||||
|
||||
// TerminateOption is a type that represents an option for terminating a container.
|
||||
type TerminateOption func(*TerminateOptions)
|
||||
|
||||
// NewTerminateOptions returns a fully initialised TerminateOptions.
|
||||
// Defaults: StopTimeout: 10 seconds.
|
||||
func NewTerminateOptions(ctx context.Context, opts ...TerminateOption) *TerminateOptions {
|
||||
timeout := time.Second * 10
|
||||
options := &TerminateOptions{
|
||||
stopTimeout: &timeout,
|
||||
ctx: ctx,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Context returns the context to use during a Terminate.
|
||||
func (o *TerminateOptions) Context() context.Context {
|
||||
return o.ctx
|
||||
}
|
||||
|
||||
// StopTimeout returns the stop timeout to use during a Terminate.
|
||||
func (o *TerminateOptions) StopTimeout() *time.Duration {
|
||||
return o.stopTimeout
|
||||
}
|
||||
|
||||
// Cleanup performs any clean up needed
|
||||
func (o *TerminateOptions) Cleanup() error {
|
||||
// TODO: simplify this when when perform the client refactor.
|
||||
if len(o.volumes) == 0 {
|
||||
return nil
|
||||
}
|
||||
apiClient, err := NewDockerClientWithOpts(o.ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("docker client: %w", err)
|
||||
}
|
||||
defer apiClient.Close()
|
||||
// Best effort to remove all volumes.
|
||||
var errs []error
|
||||
for _, volume := range o.volumes {
|
||||
if _, errRemove := apiClient.VolumeRemove(o.ctx, volume, client.VolumeRemoveOptions{Force: true}); errRemove != nil {
|
||||
errs = append(errs, fmt.Errorf("volume remove %q: %w", volume, errRemove))
|
||||
}
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// StopContext returns a TerminateOption that sets the context.
|
||||
// Default: context.Background().
|
||||
func StopContext(ctx context.Context) TerminateOption {
|
||||
return func(c *TerminateOptions) {
|
||||
c.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// StopTimeout returns a TerminateOption that sets the timeout.
|
||||
// Default: See [Container.Stop].
|
||||
func StopTimeout(timeout time.Duration) TerminateOption {
|
||||
return func(c *TerminateOptions) {
|
||||
c.stopTimeout = &timeout
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveVolumes returns a TerminateOption that sets additional volumes to remove.
|
||||
// This is useful when the container creates named volumes that should be removed
|
||||
// which are not removed by default.
|
||||
// Default: nil.
|
||||
func RemoveVolumes(volumes ...string) TerminateOption {
|
||||
return func(c *TerminateOptions) {
|
||||
c.volumes = volumes
|
||||
}
|
||||
}
|
||||
|
||||
// TerminateContainer calls [Container.Terminate] on the container if it is not nil.
|
||||
//
|
||||
// This should be called as a defer directly after [GenericContainer](...)
|
||||
// or a modules Run(...) to ensure the container is terminated when the
|
||||
// function ends.
|
||||
func TerminateContainer(container Container, options ...TerminateOption) error {
|
||||
if isNil(container) {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := container.Terminate(context.Background(), options...)
|
||||
if !isCleanupSafe(err) {
|
||||
return fmt.Errorf("terminate: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isNil returns true if val is nil or a nil instance false otherwise.
|
||||
func isNil(val any) bool {
|
||||
if val == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
valueOf := reflect.ValueOf(val)
|
||||
switch valueOf.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
|
||||
return valueOf.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user