diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 000000000..2bbdafd13 --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,21 @@ +name: Integration Tests + +on: + push: + branches: [ poc-tigron-test-framework ] + pull_request: + branches: [ poc-tigron-test-framework, main ] + +jobs: + test: + name: Integration Tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Build test container + run: docker build -t dib-test . + + - name: Run tests + run: docker run --privileged dib-test diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..104b4ea4b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +FROM ubuntu:latest AS builder + +RUN apt-get update && apt-get install -y \ + curl \ + git \ + make + +# Set up Go +RUN curl -L https://go.dev/dl/go1.24.3.linux-amd64.tar.gz | tar -C /usr/local -xz +ENV PATH=$PATH:/usr/local/go/bin + +WORKDIR /app +COPY . . + +RUN make build + +# Second stage: create a minimal image with just the binary +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y \ + curl \ + git \ + iptables \ + ca-certificates \ + gnupg + +RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +RUN echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null +RUN apt-get update && apt-get install -y docker-ce-cli + +RUN mkdir -p /tmp/buildkit && \ + curl -sSL https://github.com/moby/buildkit/releases/download/v0.12.5/buildkit-v0.12.5.linux-amd64.tar.gz | \ + tar -xz -C /tmp/buildkit && \ + mv /tmp/buildkit/bin/* /usr/local/bin/ && \ + rm -rf /tmp/buildkit + + +RUN curl -L https://go.dev/dl/go1.24.3.linux-amd64.tar.gz | tar -C /usr/local -xz +ENV PATH=$PATH:/usr/local/go/bin + +COPY --from=builder /app/dist/dib /usr/local/bin/dib + +WORKDIR /app +COPY --from=builder /app/hack /app/hack +COPY --from=builder /app/cmd /app/cmd +COPY --from=builder /app/go.mod /app/go.mod +COPY --from=builder /app/go.sum /app/go.sum +COPY --from=builder /app/pkg /app/pkg +COPY --from=builder /app/internal /app/internal + +RUN chmod +x /app/hack/test-integration.sh + +ENTRYPOINT ["/app/hack/test-integration.sh"] \ No newline at end of file diff --git a/cmd/build.go b/cmd/build.go index c1c1af957..2c047754c 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path" + "path/filepath" "runtime" "strings" @@ -152,7 +153,14 @@ func doBuild(opts dib.BuildOpts, buildArgs map[string]string) error { checkRequirements(opts) - buildPath := path.Join(workingDir, opts.BuildPath) + var buildPath string + if filepath.IsAbs(opts.BuildPath) { + // If the build path is an absolute path, use it directly + buildPath = opts.BuildPath + } else { + // Otherwise, join it with the working directory + buildPath = path.Join(workingDir, opts.BuildPath) + } logger.Infof("Building images in directory \"%s\"", buildPath) logger.Debugf("Generate DAG") diff --git a/cmd/build_test.go b/cmd/build_test.go new file mode 100644 index 000000000..230e64307 --- /dev/null +++ b/cmd/build_test.go @@ -0,0 +1,73 @@ +package cmd + +import ( + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/containerd/nerdctl/mod/tigron/expect" + "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/radiofrance/dib/pkg/testutil/dibtest" +) + +func TestBuildWithBuildkitBackendLocalOnly(t *testing.T) { + buildctlCmd := exec.Command("buildctl", "--version") + if err := buildctlCmd.Run(); err != nil { + t.Skip("Skipping test because buildctl is not available") + } + + pingCmd := exec.Command("buildctl", "debug", "workers") + if err := pingCmd.Run(); err != nil { + t.Skip("Skipping test because buildkitd is not running") + } + + tempDir, err := os.MkdirTemp("", "dib-build-test") + if err != nil { + t.Fatalf("Failed to create temporary directory: %v", err) + } + defer os.RemoveAll(tempDir) + + absPath, err := filepath.Abs(tempDir) + if err != nil { + t.Fatalf("Failed to get absolute path: %v", err) + } + tempDir = absPath + + t.Logf("Using absolute path for build: %s", tempDir) + + dockerfileContent := `FROM alpine:latest +LABEL name="test-image" +RUN echo "Hello, World!" +` + dockerfilePath := filepath.Join(tempDir, "Dockerfile") + err = os.WriteFile(dockerfilePath, []byte(dockerfileContent), 0644) + if err != nil { + t.Fatalf("Failed to create Dockerfile: %v", err) + } + + dibYamlContent := `images: + test-image: + dockerfile: Dockerfile + context: . +` + dibYamlPath := filepath.Join(tempDir, "dib.yaml") + err = os.WriteFile(dibYamlPath, []byte(dibYamlContent), 0644) + if err != nil { + t.Fatalf("Failed to create dib.yaml: %v", err) + } + + testCase := dibtest.Setup() + testCase.Command = test.Command("build", + "--backend", "buildkit", + "--local-only", + "--dry-run", // Use dry-run to avoid actually pushing images + "--no-tests", // Skip tests to simplify the build process + "--no-retag", // Skip retagging to simplify the build process + "--build-path", tempDir) // Use the temporary directory as the build path + + // We expect a successful build with exit code 0 + // The output should contain information about using the buildkit backend + testCase.Expected = test.Expects(0, nil, expect.Contains("buildkit")) + testCase.Run(t) +} diff --git a/cmd/version_test.go b/cmd/version_test.go new file mode 100644 index 000000000..4c78b1fa8 --- /dev/null +++ b/cmd/version_test.go @@ -0,0 +1,16 @@ +package cmd + +import ( + "testing" + + "github.com/containerd/nerdctl/mod/tigron/expect" + "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/radiofrance/dib/pkg/testutil/dibtest" +) + +func TestVersion(t *testing.T) { + testCase := dibtest.Setup() + testCase.Command = test.Command("version") + testCase.Expected = test.Expects(0, nil, expect.Contains("version")) + testCase.Run(t) +} diff --git a/go.mod b/go.mod index 6787a4d36..e4a3a8f7f 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2/config v1.29.14 github.com/aws/aws-sdk-go-v2/service/s3 v1.79.3 + github.com/containerd/nerdctl/mod/tigron v0.0.0-20250522084037-694c405909e6 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/distribution/reference v0.6.0 github.com/docker/cli v28.1.1+incompatible @@ -57,6 +58,7 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/creack/pty v1.1.24 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v27.5.0+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect @@ -128,7 +130,7 @@ require ( golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/go.sum b/go.sum index 30fe38c86..659cad261 100644 --- a/go.sum +++ b/go.sum @@ -68,12 +68,14 @@ github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARu github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/nerdctl/mod/tigron v0.0.0-20250522084037-694c405909e6 h1:nvUZDUfQSkK6EOaiCMl+DwAnswbDaw8f0PfTePF+qQA= +github.com/containerd/nerdctl/mod/tigron v0.0.0-20250522084037-694c405909e6/go.mod h1:gmUZh2wUVxr/msGogKUi6v9eJbP5ASO4fVYEPzHH4iI= github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8= github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -352,8 +354,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/hack/test-integration.sh b/hack/test-integration.sh new file mode 100755 index 000000000..43cf8634d --- /dev/null +++ b/hack/test-integration.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail + + +root="$(cd "$(dirname "$0")" && pwd)" + +readonly root + +readonly timeout="30m" + +cd "$root/.." + + +# Start buildkitd if not already running +if ! buildctl debug workers &> /dev/null; then + echo "Starting buildkitd..." + mkdir -p /etc/buildkit + buildkitd --oci-worker=true --containerd-worker=false & + sleep 2 +fi + +go test ./cmd/... -timeout="$timeout" -p 1 -run "TestVersion|TestBuildWithBuildkitBackendLocalOnly" -v diff --git a/pkg/testutil/dibtest/command.go b/pkg/testutil/dibtest/command.go new file mode 100644 index 000000000..37780b058 --- /dev/null +++ b/pkg/testutil/dibtest/command.go @@ -0,0 +1,36 @@ +package dibtest + +import ( + "os/exec" + "testing" + + "github.com/containerd/nerdctl/mod/tigron/test" +) + +func newDibCommand(_ test.Config, t *testing.T) *dibCommand { + binary, err := exec.LookPath("dib") + if err != nil { + t.Fatalf("unable to find binary 'dib': %v", err) + } + + ret := &dibCommand{ + GenericCommand: *(test.NewGenericCommand().(*test.GenericCommand)), + } + + ret.WithBinary(binary) + + return ret +} + +type dibCommand struct { + test.GenericCommand +} + +func (nc *dibCommand) Run(expect *test.Expected) { + nc.T().Helper() + nc.GenericCommand.Run(expect) +} + +func (nc *dibCommand) Background() { + nc.GenericCommand.Background() +} diff --git a/pkg/testutil/dibtest/test.go b/pkg/testutil/dibtest/test.go new file mode 100644 index 000000000..fa825860e --- /dev/null +++ b/pkg/testutil/dibtest/test.go @@ -0,0 +1,25 @@ +package dibtest + +import ( + "testing" + + "github.com/containerd/nerdctl/mod/tigron/test" +) + +func Setup() *test.Case { + test.Customize(&dibSetup{}) + return &test.Case{ + Env: map[string]string{}, + } +} + +type dibSetup struct { +} + +func (ns *dibSetup) CustomCommand(testCase *test.Case, t *testing.T) test.CustomizableCommand { + return newDibCommand(testCase.Config, t) +} + +func (ns *dibSetup) AmbientRequirements(testCase *test.Case, t *testing.T) { + return +}