Skip to content

Commit d58df92

Browse files
committed
tests: Fix some issues with build output
Before this change `RunTest` may return before all messages are processed. This also moves a lot of the logic around to better separate responsibilities and provide a more flexible interface that is, hopefully, easier to reason about. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent 9126ed5 commit d58df92

6 files changed

Lines changed: 201 additions & 100 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ jobs:
143143
run: docker run --rm --privileged tonistiigi/binfmt:latest --install all
144144
- name: Setup source policy
145145
uses: ./.github/actions/setup-source-policy
146+
- name: Get docker info
147+
run: |
148+
docker info
149+
docker version
150+
docker buildx version
151+
containerd --version
146152
- name: Run integration tests
147153
run: |
148154
set -ex

test/gomod_git_auth_test.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import (
1414
"strconv"
1515
"testing"
1616

17+
"github.com/moby/buildkit/client/llb"
18+
gwclient "github.com/moby/buildkit/frontend/gateway/client"
19+
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
1720
"github.com/project-dalec/dalec"
1821
"github.com/project-dalec/dalec/test/cmd/git_repo/passwd"
1922
gitservices "github.com/project-dalec/dalec/test/git_services"
2023
"github.com/project-dalec/dalec/test/testenv"
21-
"github.com/moby/buildkit/client/llb"
22-
gwclient "github.com/moby/buildkit/frontend/gateway/client"
23-
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
2424
"golang.org/x/crypto/ssh"
2525
"golang.org/x/crypto/ssh/agent"
2626
)
@@ -109,7 +109,8 @@ go {{ .ModFileGoVersion }}
109109

110110
t.Run("HTTP", func(t *testing.T) {
111111
t.Parallel()
112-
netHostBuildxEnv.RunTestOptsFirst(ctx, t, []testenv.TestRunnerOpt{
112+
113+
opts := []testenv.TestRunnerOpt{
113114
// This gives buildkit access to a secret with the name
114115
// `secretName` and the value `passwd.Password`. On the worker that
115116
// fetches the gomod dependencies, a file will be mounted at the
@@ -120,7 +121,9 @@ go {{ .ModFileGoVersion }}
120121
// requests. It is necessary but not sufficient for the buildx
121122
// instance to have host networking enabled.
122123
testenv.WithHostNetworking,
123-
}, func(ctx context.Context, client gwclient.Client) {
124+
}
125+
126+
netHostBuildxEnv.RunTest(ctx, t, func(ctx context.Context, client gwclient.Client) {
124127
// This MUST be called at the start of each test. Because we
125128
// persist the go mod cache between runs, the git tag of the
126129
// private go module needs to be unique. Within a single run of the
@@ -167,7 +170,7 @@ go {{ .ModFileGoVersion }}
167170

168171
filename := calculateFilename(ctx, t, attr, res)
169172
checkFile(ctx, t, filename, res, []byte("bar\n"))
170-
})
173+
}, opts...)
171174
})
172175

173176
t.Run("SSH", func(t *testing.T) {
@@ -182,12 +185,13 @@ go {{ .ModFileGoVersion }}
182185
pubkey, privkey := generateKeyPair(t)
183186
agentErrChan := startSSHAgent(t, privkey, sockaddr)
184187

185-
netHostBuildxEnv.RunTestOptsFirst(ctx, t, []testenv.TestRunnerOpt{
188+
opts := []testenv.TestRunnerOpt{
186189
// This tells buildkit to forward the SSH Agent socket, giving the
187190
// gomod generator worker access to the private key
188191
testenv.WithSSHSocket(sshID, sockaddr),
189192
testenv.WithHostNetworking,
190-
}, func(ctx context.Context, client gwclient.Client) {
193+
}
194+
netHostBuildxEnv.RunTest(ctx, t, func(ctx context.Context, client gwclient.Client) {
191195
// This MUST be called at the start of each test. Because we
192196
// persist the go mod cache between runs, the git tag of the
193197
// private go module needs to be unique. Within a single run of the
@@ -245,7 +249,7 @@ go {{ .ModFileGoVersion }}
245249

246250
filename := calculateFilename(ctx, t, attr, res)
247251
checkFile(ctx, t, filename, res, []byte("bar\n"))
248-
})
252+
}, opts...)
249253
})
250254
}
251255

test/linux_target_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,10 +3171,12 @@ func testLinuxPackageTestsFail(ctx context.Context, t *testing.T, cfg testLinuxC
31713171

31723172
runTest := func(target string) func(t *testing.T) {
31733173
return func(t *testing.T) {
3174+
t.Parallel()
31743175
ctx := startTestSpan(ctx, t)
31753176

31763177
for _, tc := range expectedErrs {
31773178
t.Run(tc.test.Name, func(t *testing.T) {
3179+
t.Parallel()
31783180
ctx := startTestSpan(ctx, t)
31793181

31803182
f := newLogFile(t)
@@ -3200,6 +3202,7 @@ func testLinuxPackageTestsFail(ctx context.Context, t *testing.T, cfg testLinuxC
32003202
sr := newSolveRequest(withSpec(ctx, t, spec), withBuildTarget(target))
32013203
_, err := client.Solve(ctx, sr)
32023204
assert.Assert(t, err != nil)
3205+
t.Logf("Build Error: %v", err)
32033206
// exit code errors would be here rather than in the buid logs
32043207
if !tc.isBuildError {
32053208
return
@@ -3222,9 +3225,7 @@ func testLinuxPackageTestsFail(ctx context.Context, t *testing.T, cfg testLinuxC
32223225

32233226
if !bytes.Contains(dt, []byte(tc.err.Error())) {
32243227
t.Errorf("expected error not found in logs")
3225-
t.Logf("Expected error:\n\t%v", err)
3226-
t.Log()
3227-
t.Log("---- Solve logs ----\n" + string(dt))
3228+
t.Logf("Expected error:\n\t%v", tc.err)
32283229
}
32293230
})
32303231
}

test/main_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import (
1010
"testing"
1111
"time"
1212

13-
"github.com/project-dalec/dalec/test/fixtures"
14-
"github.com/project-dalec/dalec/test/testenv"
1513
"github.com/moby/buildkit/util/tracing/delegated"
1614
"github.com/moby/buildkit/util/tracing/detect"
15+
"github.com/project-dalec/dalec/test/fixtures"
16+
"github.com/project-dalec/dalec/test/testenv"
1717
"go.opentelemetry.io/otel"
1818
"go.opentelemetry.io/otel/propagation"
1919
"go.opentelemetry.io/otel/sdk/trace"

test/testenv/build.go

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
gwclient "github.com/moby/buildkit/frontend/gateway/client"
1919
"github.com/moby/buildkit/identity"
2020
"github.com/moby/buildkit/solver/pb"
21-
"github.com/moby/buildkit/util/progress/progressui"
2221
"github.com/pkg/errors"
2322
"go.opentelemetry.io/otel"
2423
"go.opentelemetry.io/otel/codes"
@@ -176,6 +175,46 @@ var logBufferPool = &sync.Pool{New: func() any {
176175
return bytes.NewBuffer(nil)
177176
}}
178177

178+
func outputStreamStatusFn(ctx context.Context, t *testing.T) (func(*client.SolveStatus), func()) {
179+
var (
180+
warnings []*client.VertexWarning
181+
errOnce sync.Once
182+
183+
done = make(chan struct{})
184+
w = getBuildOutputStream(ctx, t, done)
185+
)
186+
187+
fn := func(msg *client.SolveStatus) {
188+
warnings = append(warnings, msg.Warnings...)
189+
for _, l := range msg.Logs {
190+
if _, err := w.Write(l.Data); err != nil {
191+
errOnce.Do(func() {
192+
// Don't spam the logs with multiple errors
193+
t.Logf("error writing log data: %v", err)
194+
})
195+
}
196+
}
197+
}
198+
199+
return fn, func() {
200+
for _, v := range warnings {
201+
t.Logf("WARNING: %s", string(v.Short))
202+
}
203+
close(done)
204+
}
205+
}
206+
207+
func multiStatusFunc(fns ...func(*client.SolveStatus)) func(*client.SolveStatus) {
208+
return func(msg *client.SolveStatus) {
209+
for _, fn := range fns {
210+
if fn == nil {
211+
continue
212+
}
213+
fn(msg)
214+
}
215+
}
216+
}
217+
179218
func getBuildOutputStream(ctx context.Context, t *testing.T, done <-chan struct{}) io.Writer {
180219
t.Helper()
181220

@@ -226,47 +265,42 @@ func getBuildOutputStream(ctx context.Context, t *testing.T, done <-chan struct{
226265
return f
227266
}
228267

229-
func displaySolveStatus(ctx context.Context, t *testing.T) chan *client.SolveStatus {
230-
ch := make(chan *client.SolveStatus)
231-
done := make(chan struct{})
232-
233-
output := getBuildOutputStream(ctx, t, done)
234-
display, err := progressui.NewDisplay(output, progressui.AutoMode, progressui.WithPhase(t.Name()))
235-
if err != nil {
236-
t.Fatal(err)
237-
}
238-
239-
go func() {
240-
defer close(done)
241-
242-
_, err := display.UpdateFrom(ctx, ch)
243-
if err != nil {
244-
t.Log(err)
268+
func fowardToSolveStatusFn(ctx context.Context, ch <-chan *client.SolveStatus, fns ...func(*client.SolveStatus)) {
269+
f := multiStatusFunc(fns...)
270+
for {
271+
select {
272+
case <-ctx.Done():
273+
return
274+
case msg, ok := <-ch:
275+
if msg != nil {
276+
f(msg)
277+
continue
278+
}
279+
if !ok {
280+
return
281+
}
245282
}
246-
}()
247-
248-
return ch
283+
}
249284
}
250285

251286
// withProjectRoot adds the current project root as the build context for the solve request.
252-
func withProjectRoot(t *testing.T, opts *client.SolveOpt) {
253-
t.Helper()
254-
287+
func withProjectRoot(opts *client.SolveOpt) error {
255288
cwd, err := os.Getwd()
256289
if err != nil {
257-
t.Fatal(err)
290+
return err
258291
}
259292

260293
projectRoot, err := lookupProjectRoot(cwd)
261294
if err != nil {
262-
t.Fatal(err)
295+
return err
263296
}
264297

265298
if opts.LocalDirs == nil {
266299
opts.LocalDirs = make(map[string]string)
267300
}
268301
opts.LocalDirs[dockerui.DefaultLocalNameContext] = projectRoot
269302
opts.LocalDirs[dockerui.DefaultLocalNameDockerfile] = projectRoot
303+
return nil
270304
}
271305

272306
// lookupProjectRoot looks up the project root from the current working directory.

0 commit comments

Comments
 (0)