make cached_image data source test actually do the thing

This commit is contained in:
Cian Johnston 2024-07-31 17:34:50 +01:00
commit 2a473d1ed4
No known key found for this signature in database
6 changed files with 176 additions and 62 deletions

View file

@ -17,3 +17,8 @@ build: terraform-provider-envbuilder
terraform-provider-envbuilder: internal/provider/*.go main.go
CGO_ENABLED=0 go build .
.PHONY: update-envbuilder-version
update-envbuilder-version:
go get github.com/coder/envbuilder@main
go mod tidy

22
go.mod
View file

@ -10,15 +10,16 @@ replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20240702054557-aa55
require (
github.com/GoogleContainerTools/kaniko v1.9.2
github.com/coder/envbuilder v0.0.0-00010101000000-000000000000
github.com/containerd/containerd v1.7.15
github.com/coder/envbuilder v1.0.0-rc.0.0.20240731115920-cacbcb8fef6c
github.com/docker/docker v26.1.0+incompatible
github.com/go-git/go-billy/v5 v5.5.0
github.com/google/go-containerregistry v0.19.1
github.com/hashicorp/terraform-plugin-docs v0.19.4
github.com/hashicorp/terraform-plugin-framework v1.10.0
github.com/hashicorp/terraform-plugin-go v0.23.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.9.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
)
require (
@ -53,7 +54,6 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/akutz/memconn v0.1.0 // indirect
@ -96,6 +96,7 @@ require (
github.com/coder/terraform-provider-coder v0.23.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/cgroups/v3 v3.0.2 // indirect
github.com/containerd/containerd v1.7.15 // indirect
github.com/containerd/continuity v0.4.3 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
@ -113,7 +114,6 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/cli v26.1.0+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v26.1.0+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.1 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
@ -140,10 +140,8 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.19.1 // indirect
github.com/google/nftables v0.2.0 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.1 // indirect
@ -221,10 +219,8 @@ require (
github.com/oklog/run v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
github.com/ory/dockertest/v3 v3.10.0 // indirect
github.com/otiai10/copy v1.14.0 // indirect
github.com/outcaste-io/ristretto v0.2.3 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
@ -248,13 +244,12 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/tailscale/certstore v0.1.1-0.20220316223106-78d6e1c49d8d // indirect
github.com/tailscale/golang-x-crypto v0.0.0-20230713185742-f0b76a10a08e // indirect
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
@ -273,9 +268,6 @@ require (
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yuin/goldmark v1.7.1 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zclconf/go-cty v1.14.4 // indirect
@ -325,5 +317,3 @@ require (
storj.io/drpc v0.0.33 // indirect
tailscale.com v1.46.1 // indirect
)
replace github.com/coder/envbuilder => /home/cian/src/coder/envbuilder

19
go.sum
View file

@ -81,8 +81,6 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
@ -188,6 +186,8 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/coder/coder/v2 v2.10.1-0.20240704130443-c2d44d16a352 h1:L/EjCuZxs5tOcqqCaASj/nu65TRYEFcTt8qRQfHZXX0=
github.com/coder/coder/v2 v2.10.1-0.20240704130443-c2d44d16a352/go.mod h1:P1KoQSgnKEAG6Mnd3YlGzAophty+yKA9VV48LpfNRvo=
github.com/coder/envbuilder v1.0.0-rc.0.0.20240731115920-cacbcb8fef6c h1:wb+i7vP0pl4R4r66dDRK7no86hFfPY+G/tCq8R9M+Cw=
github.com/coder/envbuilder v1.0.0-rc.0.0.20240731115920-cacbcb8fef6c/go.mod h1:APdfhjDHEF5gkAyhn+9MoCem+qKS84iRkNQ5mBZsajQ=
github.com/coder/kaniko v0.0.0-20240717115058-0ba2908ca4d3 h1:Q7L6cjKfw3DIyhKIcgCJEmgxnUTBajmMDrHxXvxgBZs=
github.com/coder/kaniko v0.0.0-20240717115058-0ba2908ca4d3/go.mod h1:YMK7BlxerzLlMwihGxNWUaFoN9LXCij4P+w/8/fNlcM=
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs=
@ -404,8 +404,6 @@ github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8
github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@ -636,16 +634,12 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
@ -801,13 +795,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
@ -845,6 +832,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruO
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.24.0 h1:JYE2HM7pZbOt5Jhk8ndWZTUWYOVift2cHjXVMkPdmdc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.24.0/go.mod h1:yMb/8c6hVsnma0RpsBMNo0fEiQKeclawtgaIaOp2MLY=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=

View file

@ -291,7 +291,7 @@ func (d *CachedImageDataSource) Read(ctx context.Context, req datasource.ReadReq
InitArgs: "",
InitCommand: "",
InitScript: "",
LayerCacheDir: "", // This will be ignored, as we are exclusively using the cache repo.
LayerCacheDir: "",
PostStartScriptPath: "",
PushImage: false,
SetupScript: "",
@ -314,8 +314,8 @@ func (d *CachedImageDataSource) Read(ctx context.Context, req datasource.ReadReq
// TODO(mafredri): Implement the actual data source read logic.
data.ID = types.StringValue("cached-image-id")
data.Exists = types.BoolValue(false)
data.Image = data.BuilderImage
data.Exists = types.BoolValue(true)
data.Image = types.StringValue(fmt.Sprintf("%s@%s", data.CacheRepo, digest.String()))
// Compute the env attribute from the config map.
// TODO(mafredri): Convert any other relevant attributes given via schema.

View file

@ -4,45 +4,62 @@
package provider
import (
"context"
"fmt"
"strings"
"testing"
"time"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
func TestAccCachedImageDataSource(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
t.Cleanup(cancel)
files := map[string]string{
"devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
"Dockerfile": `FROM ubuntu:latest
RUN apt-get update && apt-get install -y cowsay`,
}
deps := setup(ctx, t, files)
tfCfg := fmt.Sprintf(`data "envbuilder_cached_image" "test" {
builder_image = %q
devcontainer_dir = %q
git_url = %q
extra_env = {
"FOO" : "bar"
}
cache_repo = %q
}`, deps.BuilderImage, deps.RepoDir, deps.RepoDir, deps.CacheRepo)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Read testing
{
Config: testAccCachedImageDataSourceConfig,
Config: tfCfg,
Check: resource.ComposeAggregateTestCheckFunc(
// Input
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.ENVBUILDER_VERBOSE", "true"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", "https://github.com/coder/envbuilder-starter-devcontainer"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", deps.CacheRepo),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.FOO", "bar"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", deps.RepoDir),
// Should be empty
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_username"),
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_password"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", "localhost:5000/local/test-cache"),
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "cache_ttl_days"),
// Computed
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "id", "cached-image-id"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "false"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "image", "ghcr.io/coder/envbuilder:latest"),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "env.0", "ENVBUILDER_VERBOSE=\"true\""),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "true"),
resource.TestCheckResourceAttrSet("data.envbuilder_cached_image.test", "image"),
resource.TestCheckResourceAttrWith("data.envbuilder_cached_image.test", "image", func(value string) error {
if !strings.HasPrefix(value, deps.CacheRepo) {
return fmt.Errorf("expected prefix %q", deps.CacheRepo)
}
return nil
}),
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "env.0", "FOO=\"bar\""),
),
},
},
})
}
const testAccCachedImageDataSourceConfig = `
data "envbuilder_cached_image" "test" {
builder_image = "ghcr.io/coder/envbuilder:latest"
git_url = "https://github.com/coder/envbuilder-starter-devcontainer"
cache_repo = "localhost:5000/local/test-cache"
extra_env = {
"ENVBUILDER_VERBOSE" : "true"
}
}
`

View file

@ -4,16 +4,29 @@
package provider
import (
"bufio"
"context"
"fmt"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"github.com/google/go-containerregistry/pkg/registry"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/ory/dockertest/v3"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/stretchr/testify/require"
)
const (
testContainerLabel = "terraform-provider-envbuilder-test"
)
// testAccProtoV6ProviderFactories are used to instantiate a provider during
// acceptance testing. The factory function will be invoked for every Terraform
// CLI command executed to create a provider server to which the CLI can
@ -28,15 +41,6 @@ func testAccPreCheck(t *testing.T) {
// function.
}
func seedEnvbuilderCache(t *testing.T, image string, env map[string]string) {
t.Helper()
pool, err := dockertest.NewPool("")
require.NoError(t, err, "setup docker test pool")
require.NoError(t, pool.Client.Ping(), "could not connect to docker daemon")
}
// envs turns a map[string]string of envs to a slice of string in the form k1=v1,k2=v2,...
func envs(m map[string]string) (ss []string) {
var sb strings.Builder
@ -49,3 +53,112 @@ func envs(m map[string]string) (ss []string) {
}
return ss
}
type testDependencies struct {
BuilderImage string
RepoDir string
CacheRepo string
}
func setup(ctx context.Context, t testing.TB, files map[string]string) testDependencies {
t.Helper()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err, "init docker client")
t.Cleanup(func() { _ = cli.Close() })
// TODO: envbuilder creates /.envbuilder/bin/envbuilder owned by root:root which we are unable to clean up.
// This causes tests to fail.
repoDir := t.TempDir()
cacheRepo := runLocalRegistry(t)
writeFiles(t, files, repoDir)
envbuilderImage := getEnvOrDefault("ENVBUILDER_IMAGE", "ghcr.io/coder/envbuilder-preview")
envbuilderVersion := getEnvOrDefault("ENVBUILDER_VERSION", "latest")
refStr := envbuilderImage + ":" + envbuilderVersion
// Run envbuilder using this dir as a local layer cache
ctr, err := cli.ContainerCreate(ctx, &container.Config{
Image: refStr,
Env: []string{
"ENVBUILDER_CACHE_REPO=" + cacheRepo,
"ENVBUILDER_DEVCONTAINER_DIR=" + repoDir,
"ENVBUILDER_EXIT_ON_BUILD_FAILURE=true",
"ENVBUILDER_INIT_SCRIPT=exit",
"ENVBUILDER_PUSH_IMAGE=true",
},
Labels: map[string]string{
testContainerLabel: "true",
}}, &container.HostConfig{
NetworkMode: container.NetworkMode("host"),
Binds: []string{repoDir + ":" + repoDir},
}, nil, nil, "")
require.NoError(t, err, "failed to run envbuilder to seed cache")
t.Cleanup(func() {
_ = cli.ContainerRemove(ctx, ctr.ID, container.RemoveOptions{
RemoveVolumes: true,
Force: true,
})
})
err = cli.ContainerStart(ctx, ctr.ID, container.StartOptions{})
require.NoError(t, err)
rawLogs, err := cli.ContainerLogs(ctx, ctr.ID, container.LogsOptions{
ShowStdout: true,
ShowStderr: true,
Follow: true,
Timestamps: false,
})
require.NoError(t, err)
defer rawLogs.Close()
scanner := bufio.NewScanner(rawLogs)
SCANLOGS:
for {
select {
case <-ctx.Done():
require.Fail(t, "envbuilder did not finish running in time")
default:
if !scanner.Scan() {
require.Fail(t, "envbuilder did not run successfully")
}
log := scanner.Text()
t.Logf("envbuilder: %s", log)
if strings.Contains(log, "=== Running the init command") {
break SCANLOGS
}
}
}
return testDependencies{
BuilderImage: refStr,
CacheRepo: cacheRepo,
RepoDir: repoDir,
}
}
func getEnvOrDefault(env, defVal string) string {
if val := os.Getenv(env); val != "" {
return val
}
return defVal
}
func writeFiles(t testing.TB, files map[string]string, destPath string) {
for relPath, content := range files {
absPath := filepath.Join(destPath, relPath)
d := filepath.Dir(absPath)
bs := []byte(content)
require.NoError(t, os.MkdirAll(d, 0o755))
require.NoError(t, os.WriteFile(absPath, bs, 0o644))
t.Logf("wrote %d bytes to %s", len(bs), absPath)
}
}
func runLocalRegistry(t testing.TB) string {
t.Helper()
tempDir := t.TempDir()
regHandler := registry.New(registry.WithBlobHandler(registry.NewDiskBlobHandler(tempDir)))
regSrv := httptest.NewServer(regHandler)
t.Cleanup(func() { regSrv.Close() })
regSrvURL, err := url.Parse(regSrv.URL)
require.NoError(t, err)
return fmt.Sprintf("localhost:%s/test", regSrvURL.Port())
}