mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
203 lines
4.6 KiB
Go
203 lines
4.6 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/ory/dockertest/v3"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/egymgmbh/go-prefix-writer/prefixer"
|
|
"github.com/formancehq/go-libs/httpserver"
|
|
serviceutils "github.com/formancehq/go-libs/service"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type service interface {
|
|
load(context.Context, *Test) error
|
|
unload(context.Context, *Test) error
|
|
}
|
|
|
|
type cobraCommandService struct {
|
|
args func(*Test) []string
|
|
routingName string
|
|
routingFunc func(path, method string) bool
|
|
command func() *cobra.Command
|
|
name string
|
|
cancel func()
|
|
started bool
|
|
appContext context.Context
|
|
running bool
|
|
}
|
|
|
|
func (c *cobraCommandService) load(ctx context.Context, t *Test) error {
|
|
command := c.command()
|
|
command.SetArgs(c.args(t))
|
|
|
|
writer := prefixer.New(t.env.writer, func() string {
|
|
return c.name + " | "
|
|
})
|
|
command.SetOut(writer)
|
|
command.SetErr(writer)
|
|
|
|
c.appContext = serviceutils.ContextWithLifecycle(ctx)
|
|
c.appContext = httpserver.ContextWithServerInfo(c.appContext)
|
|
c.appContext, c.cancel = context.WithCancel(c.appContext)
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- command.ExecuteContext(c.appContext)
|
|
}()
|
|
select {
|
|
case <-serviceutils.Ready(c.appContext):
|
|
if c.routingFunc != nil {
|
|
t.registerServiceToRoute(c.routingName, routing{
|
|
port: uint16(httpserver.Port(c.appContext)),
|
|
routingFunc: c.routingFunc,
|
|
})
|
|
}
|
|
t.registerServiceToRoute(c.name, routing{port: uint16(httpserver.Port(c.appContext))})
|
|
c.running = true
|
|
|
|
return nil
|
|
case err := <-errCh:
|
|
return err
|
|
case <-time.After(30 * time.Second):
|
|
return fmt.Errorf("timeout waiting for service '%s' to be properly started", c.name)
|
|
}
|
|
}
|
|
|
|
func (c cobraCommandService) unload(context.Context, *Test) error {
|
|
if !c.running {
|
|
return nil
|
|
}
|
|
c.cancel()
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-serviceutils.Stopped(c.appContext):
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (c *cobraCommandService) WithArgs(fn func(*Test) []string) *cobraCommandService {
|
|
c.args = fn
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *cobraCommandService) WithRoutingFunc(name string, fn func(path, method string) bool) *cobraCommandService {
|
|
c.routingName = name
|
|
c.routingFunc = fn
|
|
|
|
return c
|
|
}
|
|
|
|
var _ service = (*cobraCommandService)(nil)
|
|
|
|
func NewCommandService(name string, factory func() *cobra.Command) *cobraCommandService {
|
|
return &cobraCommandService{
|
|
command: factory,
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
type HealthCheck func(test *Test, container *dockertest.Resource) bool
|
|
|
|
type dockerContainerService struct {
|
|
entrypoint []string
|
|
repository string
|
|
tag string
|
|
mounts func(*Test) []string
|
|
healthCheck HealthCheck
|
|
env func(*Test) []string
|
|
resource *dockertest.Resource
|
|
}
|
|
|
|
func (d *dockerContainerService) load(ctx context.Context, test *Test) error {
|
|
|
|
var err error
|
|
d.resource, err = test.env.dockerPool.RunWithOptions(&dockertest.RunOptions{
|
|
Repository: d.repository,
|
|
Tag: d.tag,
|
|
Mounts: d.mounts(test),
|
|
Tty: true,
|
|
Entrypoint: d.entrypoint,
|
|
Env: d.env(test),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
go func() {
|
|
reader, _ := test.env.dockerClient.ContainerLogs(TestContext(), d.resource.Container.ID, container.LogsOptions{
|
|
ShowStdout: true,
|
|
ShowStderr: true,
|
|
Follow: true,
|
|
Details: false,
|
|
})
|
|
if reader != nil {
|
|
_, _ = io.Copy(prefixer.New(test.env.writer, func() string {
|
|
return "benthos | "
|
|
}), reader)
|
|
}
|
|
}()
|
|
|
|
healthCheckContext, cancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer cancel()
|
|
if d.healthCheck != nil {
|
|
for {
|
|
if d.healthCheck(test, d.resource) {
|
|
break
|
|
}
|
|
select {
|
|
case <-healthCheckContext.Done():
|
|
return healthCheckContext.Err()
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *dockerContainerService) unload(ctx context.Context, test *Test) error {
|
|
if d.resource == nil {
|
|
return nil
|
|
}
|
|
return test.env.dockerPool.Purge(d.resource)
|
|
}
|
|
|
|
func (d *dockerContainerService) WithEntrypoint(entrypoint []string) *dockerContainerService {
|
|
d.entrypoint = entrypoint
|
|
|
|
return d
|
|
}
|
|
|
|
func (d *dockerContainerService) WithEnv(f func(*Test) []string) *dockerContainerService {
|
|
d.env = f
|
|
|
|
return d
|
|
}
|
|
|
|
func (d *dockerContainerService) WithMounts(mounts func(test *Test) []string) *dockerContainerService {
|
|
d.mounts = mounts
|
|
|
|
return d
|
|
}
|
|
|
|
func (d *dockerContainerService) WithHealthCheck(fn HealthCheck) *dockerContainerService {
|
|
d.healthCheck = fn
|
|
|
|
return d
|
|
}
|
|
|
|
var _ service = (*dockerContainerService)(nil)
|
|
|
|
func NewDockerService(repository, tag string) *dockerContainerService {
|
|
return &dockerContainerService{
|
|
repository: repository,
|
|
tag: tag,
|
|
}
|
|
}
|