Forklift buildx provider
This commit is contained in:
374
provider/internal/client_test.go
Normal file
374
provider/internal/client_test.go
Normal file
@@ -0,0 +1,374 @@
|
||||
// Copyright 2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
user := "pulumibot"
|
||||
if u := os.Getenv("DOCKER_HUB_USER"); u != "" {
|
||||
user = u
|
||||
}
|
||||
password := os.Getenv("DOCKER_HUB_PASSWORD")
|
||||
address := "docker.io"
|
||||
|
||||
cli := testcli(t, true, Registry{
|
||||
Address: address,
|
||||
Username: user,
|
||||
Password: password,
|
||||
})
|
||||
|
||||
_, err := cli.Client().RegistryLogin(context.Background(), registry.AuthConfig{ServerAddress: address})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCustomHost(t *testing.T) {
|
||||
socket := "unix:///foo/bar.sock"
|
||||
|
||||
//nolint:paralleltest // not compatible with Setenv
|
||||
t.Run("env", func(t *testing.T) {
|
||||
t.Setenv("DOCKER_HOST", socket)
|
||||
|
||||
h, err := newHost(nil)
|
||||
require.NoError(t, err)
|
||||
cli, err := wrap(h)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, socket, cli.Client().DaemonHost())
|
||||
assert.Equal(t, socket, cli.DockerEndpoint().Host)
|
||||
})
|
||||
|
||||
t.Run("config", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
h, err := newHost(&Config{Host: socket})
|
||||
require.NoError(t, err)
|
||||
cli, err := wrap(h)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, socket, cli.Client().DaemonHost())
|
||||
assert.Equal(t, socket, cli.DockerEndpoint().Host)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Workaround for https://github.com/pulumi/pulumi-go-provider/issues/159
|
||||
ctrl, ctx := gomock.WithContext(context.Background(), t)
|
||||
pctx := NewMockProviderContext(ctrl)
|
||||
pctx.EXPECT().Log(gomock.Any(), gomock.Any()).AnyTimes()
|
||||
pctx.EXPECT().LogStatus(gomock.Any(), gomock.Any()).AnyTimes()
|
||||
pctx.EXPECT().Done().Return(ctx.Done()).AnyTimes()
|
||||
pctx.EXPECT().Value(gomock.Any()).DoAndReturn(func(key any) any { return ctx.Value(key) }).AnyTimes()
|
||||
pctx.EXPECT().Err().Return(ctx.Err()).AnyTimes()
|
||||
pctx.EXPECT().Deadline().Return(ctx.Deadline()).AnyTimes()
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
exampleContext := BuildContext{Context: Context{Location: "../../examples/app"}}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
skip bool
|
||||
args ImageArgs
|
||||
|
||||
auths []Registry
|
||||
}{
|
||||
{
|
||||
name: "multiPlatform",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.multiPlatform",
|
||||
},
|
||||
Platforms: []Platform{"plan9/amd64", "plan9/arm64"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "registryPush",
|
||||
skip: os.Getenv("DOCKER_HUB_PASSWORD") == "",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Tags: []string{"docker.io/pulumibot/buildkit-e2e:unit"},
|
||||
Push: true,
|
||||
},
|
||||
auths: []Registry{{
|
||||
Address: "docker.io",
|
||||
Username: "pulumibot",
|
||||
Password: os.Getenv("DOCKER_HUB_PASSWORD"),
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "cached",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Tags: []string{"cached"},
|
||||
CacheTo: []CacheTo{{Local: &CacheToLocal{
|
||||
Dest: filepath.Join(tmpdir, "cache"),
|
||||
CacheWithMode: CacheWithMode{Mode: "max"},
|
||||
}}},
|
||||
CacheFrom: []CacheFrom{{Local: &CacheFromLocal{
|
||||
Src: filepath.Join(tmpdir, "cache"),
|
||||
}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buildArgs",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.buildArgs",
|
||||
},
|
||||
BuildArgs: map[string]string{
|
||||
"SET_ME_TO_TRUE": "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "extraHosts",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.extraHosts",
|
||||
},
|
||||
AddHosts: []string{
|
||||
"metadata.google.internal:169.254.169.254",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sshMount",
|
||||
skip: os.Getenv("SSH_AUTH_SOCK") == "",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.sshMount",
|
||||
},
|
||||
SSH: []SSH{{ID: "default"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secrets",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.secrets",
|
||||
},
|
||||
Secrets: map[string]string{
|
||||
"password": "hunter2",
|
||||
},
|
||||
NoCache: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "labels",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Labels: map[string]string{
|
||||
"description": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "target",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.target",
|
||||
},
|
||||
Target: "build-me",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namedContext",
|
||||
args: ImageArgs{
|
||||
Context: BuildContext{
|
||||
Context: Context{
|
||||
Location: "../../examples/app",
|
||||
},
|
||||
Named: NamedContexts{
|
||||
"golang:latest": Context{
|
||||
Location: "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984",
|
||||
},
|
||||
},
|
||||
},
|
||||
Dockerfile: Dockerfile{
|
||||
Location: "../../examples/app/Dockerfile.namedContexts",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remoteContext",
|
||||
args: ImageArgs{
|
||||
Context: BuildContext{
|
||||
Context: Context{
|
||||
Location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remoteContextWithInline",
|
||||
args: ImageArgs{
|
||||
Context: BuildContext{
|
||||
Context: Context{
|
||||
Location: "https://github.com/docker-library/hello-world.git",
|
||||
},
|
||||
},
|
||||
Dockerfile: Dockerfile{
|
||||
Inline: dedent(`
|
||||
FROM busybox
|
||||
COPY hello.c ./
|
||||
`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inline",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Dockerfile: Dockerfile{
|
||||
Inline: dedent(`
|
||||
FROM alpine
|
||||
RUN echo 👍
|
||||
`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dockerLoad",
|
||||
args: ImageArgs{
|
||||
Context: exampleContext,
|
||||
Load: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Add an exec: true version for all of our test cases.
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
tt.name = "exec-" + tt.name
|
||||
tt.args.Exec = true
|
||||
tmpdir := filepath.Join(t.TempDir(), "exec")
|
||||
for _, c := range tt.args.CacheTo {
|
||||
if c.Local != nil {
|
||||
c.Local.Dest = tmpdir
|
||||
}
|
||||
}
|
||||
for _, c := range tt.args.CacheFrom {
|
||||
if c.Local != nil {
|
||||
c.Local.Src = tmpdir
|
||||
}
|
||||
}
|
||||
tests = append(tests, tt)
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if tt.skip {
|
||||
t.Skip()
|
||||
}
|
||||
cli := testcli(t, true, tt.auths...)
|
||||
|
||||
build, err := tt.args.toBuild(pctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = cli.Build(pctx, build)
|
||||
assert.NoError(t, err, cli.err.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildkitEnabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli := testcli(t, false)
|
||||
ok, err := cli.BuildKitEnabled()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
func TestInspect(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli := testcli(t, false)
|
||||
descriptors, err := cli.Inspect(context.Background(), "pulumibot/myapp:buildx")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "application/vnd.docker.distribution.manifest.v2+json", descriptors[0].MediaType)
|
||||
}
|
||||
|
||||
func TestNormalizatReference(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
ref string
|
||||
want string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
ref: "foo",
|
||||
want: "docker.io/library/foo:latest",
|
||||
},
|
||||
{
|
||||
ref: "pulumi/pulumi:v3.100.0",
|
||||
want: "docker.io/pulumi/pulumi:v3.100.0",
|
||||
},
|
||||
{
|
||||
ref: "invalid:ref:format",
|
||||
wantErr: "invalid reference format",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.ref, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ref, err := normalizeReference(tt.ref)
|
||||
if err != nil {
|
||||
assert.ErrorContains(t, err, tt.wantErr)
|
||||
} else {
|
||||
assert.Equal(t, ref.String(), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// testcli returns a new standalone CLI instance. Set ping to true if a live
|
||||
// daemon is required -- the test will be skipped if the daemon is not available.
|
||||
func testcli(t *testing.T, ping bool, auths ...Registry) *cli {
|
||||
h, err := newHost(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
cli, err := wrap(h, auths...)
|
||||
require.NoError(t, err)
|
||||
|
||||
if ping {
|
||||
_, err := cli.Client().Ping(context.Background())
|
||||
if err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
}
|
||||
|
||||
return cli
|
||||
}
|
||||
Reference in New Issue
Block a user