add better unit test for combind logging
This commit is contained in:
@@ -33,9 +33,9 @@ func toSpec(spec *Spec, step *Step) *specgen.SpecGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
volume := specgen.ContainerStorageConfig{
|
volume := specgen.ContainerStorageConfig{
|
||||||
Image: step.Image,
|
WorkDir: step.WorkingDir,
|
||||||
WorkDir: step.WorkingDir,
|
CreateWorkingDir: true,
|
||||||
ShmSize: toPtr(step.ShmSize),
|
ShmSize: toPtr(step.ShmSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeSet := toVolumeSet(spec, step)
|
volumeSet := toVolumeSet(spec, step)
|
||||||
@@ -109,7 +109,7 @@ func toSpec(spec *Spec, step *Step) *specgen.SpecGenerator {
|
|||||||
ContainerResourceConfig: resource,
|
ContainerResourceConfig: resource,
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("creating [config=%+v]", config)
|
logrus.Tracef("creating [config=%+v]", config)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,12 +238,21 @@ func (e *Podman) Run(ctx context.Context, specv runtime.Spec, stepv runtime.Step
|
|||||||
}
|
}
|
||||||
defer logs.Close()
|
defer logs.Close()
|
||||||
} else {
|
} else {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
multiWriter := io.MultiWriter(output, &buf)
|
||||||
|
|
||||||
logger.FromContext(ctx).Tracef("tail logging...")
|
logger.FromContext(ctx).Tracef("tail logging...")
|
||||||
err = e.tail(ctx, step.ID, output)
|
err = e.tail(ctx, step.ID, multiWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.FromContext(ctx).
|
||||||
|
WithError(err).
|
||||||
|
Errorf("failed to tail logs")
|
||||||
return nil, errors.TrimExtraInfo(err)
|
return nil, errors.TrimExtraInfo(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.FromContext(ctx).Debugf("[tail_logs=%s]", buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the response
|
// wait for the response
|
||||||
return e.waitRetry(ctx, step.ID)
|
return e.waitRetry(ctx, step.ID)
|
||||||
}
|
}
|
||||||
@@ -408,17 +417,17 @@ func (e *Podman) tail(ctx context.Context, id string, output io.Writer) error {
|
|||||||
Timestamps: toPtr(false),
|
Timestamps: toPtr(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
out := make(chan string, 100)
|
out := make(chan string, 1000)
|
||||||
error := make(chan string, 100)
|
error := make(chan string, 1000)
|
||||||
|
|
||||||
err := containers.Logs(e.conn, id, &opts, out, error)
|
err := containers.Logs(e.conn, id, &opts, out, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
logs := NewChansReadClose(ctx, out, error)
|
||||||
|
|
||||||
logger.FromContext(ctx).Debugf("starting log goroutine [id=%s]...", id)
|
logger.FromContext(ctx).Debugf("starting log goroutine [id=%s]...", id)
|
||||||
go func() {
|
go func() {
|
||||||
logs := NewChansReadClose(ctx, out, error)
|
|
||||||
io.Copy(output, logs)
|
io.Copy(output, logs)
|
||||||
logs.Close()
|
logs.Close()
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/drone/runner-go/environ"
|
"github.com/drone/runner-go/environ"
|
||||||
"github.com/drone/runner-go/pipeline/runtime"
|
"github.com/drone/runner-go/pipeline/runtime"
|
||||||
)
|
)
|
||||||
@@ -137,6 +139,17 @@ type (
|
|||||||
|
|
||||||
func (s *Spec) StepLen() int { return len(s.Steps) }
|
func (s *Spec) StepLen() int { return len(s.Steps) }
|
||||||
func (s *Spec) StepAt(i int) runtime.Step { return s.Steps[i] }
|
func (s *Spec) StepAt(i int) runtime.Step { return s.Steps[i] }
|
||||||
|
func (s *Spec) String() string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
Platform: %+v
|
||||||
|
Steps: %+v
|
||||||
|
Internal: %+v
|
||||||
|
Volumes: %+v
|
||||||
|
Network: %+v
|
||||||
|
}`, s.Platform, s.Steps, s.Internal,
|
||||||
|
s.Volumes, s.Network,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// implements the Secret interface
|
// implements the Secret interface
|
||||||
@@ -166,3 +179,48 @@ func (s *Step) Clone() runtime.Step {
|
|||||||
dst.Envs = environ.Combine(s.Envs)
|
dst.Envs = environ.Combine(s.Envs)
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
func (s *Step) String() string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
ID: %s
|
||||||
|
Auth: %+v
|
||||||
|
Command: %+v
|
||||||
|
CPUPeriod: %d
|
||||||
|
CPUQuota: %d
|
||||||
|
CPUShares: %d
|
||||||
|
CPUSet: %+v
|
||||||
|
Detach: %t
|
||||||
|
DependsOn: %+v
|
||||||
|
Devices: %+v
|
||||||
|
DNS: %+v
|
||||||
|
DNSSearch: %+v
|
||||||
|
Entrypoint: %+v
|
||||||
|
Envs: %+v
|
||||||
|
ErrPolicy: %+v
|
||||||
|
ExtraHosts: %+v
|
||||||
|
IgnoreStdout: %t
|
||||||
|
IgnoreStderr: %t
|
||||||
|
Image: %s
|
||||||
|
Labels: %+v
|
||||||
|
MemSwapLimit: %d
|
||||||
|
MemLimit: %d
|
||||||
|
Name: %s
|
||||||
|
Network: %s
|
||||||
|
Networks: %+v
|
||||||
|
Privileged: %t
|
||||||
|
Pull: %+v
|
||||||
|
RunPolicy: %+v
|
||||||
|
Secrets: %+v
|
||||||
|
ShmSize: %d
|
||||||
|
User: %s
|
||||||
|
Volumes: %+v
|
||||||
|
WorkingDir: %s
|
||||||
|
}`, s.ID, s.Auth, s.Command, s.CPUPeriod,
|
||||||
|
s.CPUQuota, s.CPUShares, s.CPUSet, s.Detach,
|
||||||
|
s.DependsOn, s.Devices, s.DNS, s.DNSSearch,
|
||||||
|
s.Entrypoint, s.Envs, s.ErrPolicy, s.ExtraHosts,
|
||||||
|
s.IgnoreStdout, s.IgnoreStderr, s.Image, s.Labels,
|
||||||
|
s.MemSwapLimit, s.MemLimit, s.Name, s.Network,
|
||||||
|
s.Networks, s.Privileged, s.Pull, s.RunPolicy,
|
||||||
|
s.Secrets, s.ShmSize, s.User, s.Volumes, s.WorkingDir,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ func (c *ReaderClose) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
n += copy(p, []byte(value.String()))
|
n += copy(p, []byte(value.String()))
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, io.EOF
|
return n, io.EOF
|
||||||
|
|||||||
@@ -7,21 +7,24 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChansToReader(t *testing.T) {
|
func TestChansToReader(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
stdout := make(chan string, 1000)
|
stdout := make(chan string, 1000)
|
||||||
|
stderr := make(chan string, 1000)
|
||||||
|
|
||||||
logs := NewChansReadClose(ctx, stdout)
|
logs := NewChansReadClose(ctx, stdout, stderr)
|
||||||
|
|
||||||
mockLogs := []string{
|
mockLogs := []string{
|
||||||
"\u0008",
|
|
||||||
"this is a log 1\n",
|
"this is a log 1\n",
|
||||||
"this is a log 2\n",
|
"this is a log 2\n",
|
||||||
"this is a log 3\n",
|
"this is a log 3\n",
|
||||||
@@ -38,17 +41,71 @@ func TestChansToReader(t *testing.T) {
|
|||||||
|
|
||||||
go func(mock []string) {
|
go func(mock []string) {
|
||||||
for i := range mock {
|
for i := range mock {
|
||||||
time.Sleep(2)
|
time.Sleep(500 * time.Millisecond)
|
||||||
fmt.Printf("sending [mock=%s]\n", mock[i])
|
if i%3 == 0 {
|
||||||
stdout <- mock[i]
|
stderr <- "err " + mock[i]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout <- "out " + mock[i]
|
||||||
}
|
}
|
||||||
fmt.Println("closing channel...")
|
|
||||||
logs.Close()
|
logs.Close()
|
||||||
}(mockLogs)
|
}(mockLogs)
|
||||||
|
|
||||||
fmt.Println("starting std copy...")
|
|
||||||
output := bytes.NewBuffer([]byte{})
|
output := bytes.NewBuffer([]byte{})
|
||||||
io.Copy(output, logs)
|
n, err := io.Copy(output, logs)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to copy reader to ouput [error=%s]", err.Error())
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Print(output.String())
|
logrus.Infof("[bytes=%d] [logs=%s]\n",
|
||||||
|
n, output.String(),
|
||||||
|
)
|
||||||
|
splitResult := strings.Split(output.String(), "\n")
|
||||||
|
for i := range mockLogs {
|
||||||
|
if i%3 == 0 {
|
||||||
|
if !checkStrErr(i, splitResult[i]) {
|
||||||
|
logrus.Errorf("logs do not match\n\t[expect=%s]\n\t[got=%s]",
|
||||||
|
"err "+mockLogs[i], splitResult[i],
|
||||||
|
)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkStrOut(i, splitResult[i]) {
|
||||||
|
logrus.Errorf("logs do not match\n\t[expect=%s]\n\t[got=%s]",
|
||||||
|
"out "+mockLogs[i], splitResult[i],
|
||||||
|
)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStrErr(line int, strerr string) bool {
|
||||||
|
if strerr[:3] != "err" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkStr(line, strerr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStrOut(line int, strout string) bool {
|
||||||
|
if strout[:3] != "out" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkStr(line, strout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStr(line int, str string) bool {
|
||||||
|
split := strings.Split(str, " ")
|
||||||
|
|
||||||
|
n, err := strconv.Atoi(split[len(split)-1])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return line+1 == n
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user