github.com/windmeup/goreleaser@v1.21.95/internal/pipe/blob/blob_minio_test.go (about) 1 package blob 2 3 import ( 4 "fmt" 5 "io" 6 "log" 7 "net/http" 8 "os" 9 "path/filepath" 10 "testing" 11 12 "github.com/ory/dockertest/v3" 13 "github.com/ory/dockertest/v3/docker" 14 "github.com/stretchr/testify/require" 15 "github.com/windmeup/goreleaser/internal/artifact" 16 "github.com/windmeup/goreleaser/internal/testctx" 17 "github.com/windmeup/goreleaser/internal/testlib" 18 "github.com/windmeup/goreleaser/pkg/config" 19 "github.com/windmeup/goreleaser/pkg/context" 20 "gocloud.dev/blob" 21 ) 22 23 const ( 24 minioUser = "minio" 25 minioPwd = "miniostorage" 26 containerName = "goreleaserTestMinio" 27 ) 28 29 var listen string 30 31 func TestMain(m *testing.M) { 32 prepareEnv() 33 34 requireNoErr := func(err error) { 35 if err != nil { 36 log.Fatal(err) 37 } 38 } 39 40 pool := testlib.MustDockerPool(log.Default()) 41 testlib.MustKillContainer(log.Default(), containerName) 42 43 resource, err := pool.RunWithOptions(&dockertest.RunOptions{ 44 Name: containerName, 45 Repository: "minio/minio", 46 Tag: "latest", 47 Env: []string{ 48 "MINIO_ROOT_USER=" + minioUser, 49 "MINIO_ROOT_PASSWORD=" + minioPwd, 50 }, 51 ExposedPorts: []string{"9000", "9001"}, 52 Cmd: []string{"server", "/data", "--console-address", ":9001"}, 53 }, func(hc *docker.HostConfig) { 54 hc.AutoRemove = true 55 }) 56 requireNoErr(err) 57 requireNoErr(pool.Retry(func() error { 58 _, err := http.Get(fmt.Sprintf("http://localhost:%s/minio/health/ready", resource.GetPort("9000/tcp"))) 59 return err 60 })) 61 listen = "localhost:" + resource.GetPort("9000/tcp") 62 63 code := m.Run() 64 65 requireNoErr(pool.Purge(resource)) 66 os.Exit(code) 67 } 68 69 func TestMinioUpload(t *testing.T) { 70 name := "basic" 71 folder := t.TempDir() 72 srcpath := filepath.Join(folder, "source.tar.gz") 73 tgzpath := filepath.Join(folder, "bin.tar.gz") 74 debpath := filepath.Join(folder, "bin.deb") 75 checkpath := filepath.Join(folder, "check.txt") 76 sigpath := filepath.Join(folder, "f.sig") 77 certpath := filepath.Join(folder, "f.pem") 78 require.NoError(t, os.WriteFile(checkpath, []byte("fake checksums"), 0o744)) 79 require.NoError(t, os.WriteFile(srcpath, []byte("fake\nsrc"), 0o744)) 80 require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744)) 81 require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744)) 82 require.NoError(t, os.WriteFile(sigpath, []byte("fake\nsig"), 0o744)) 83 require.NoError(t, os.WriteFile(certpath, []byte("fake\ncert"), 0o744)) 84 ctx := testctx.NewWithCfg(config.Project{ 85 Dist: folder, 86 ProjectName: "testupload", 87 Blobs: []config.Blob{ 88 { 89 Provider: "s3", 90 Bucket: name, 91 Region: "us-east", 92 Endpoint: "http://" + listen, 93 IDs: []string{"foo", "bar"}, 94 ExtraFiles: []config.ExtraFile{ 95 { 96 Glob: "./testdata/*.golden", 97 }, 98 }, 99 }, 100 }, 101 }, testctx.WithCurrentTag("v1.0.0")) 102 ctx.Artifacts.Add(&artifact.Artifact{ 103 Type: artifact.Checksum, 104 Name: "checksum.txt", 105 Path: checkpath, 106 }) 107 ctx.Artifacts.Add(&artifact.Artifact{ 108 Type: artifact.Signature, 109 Name: "checksum.txt.sig", 110 Path: sigpath, 111 Extra: map[string]interface{}{ 112 artifact.ExtraID: "foo", 113 }, 114 }) 115 ctx.Artifacts.Add(&artifact.Artifact{ 116 Type: artifact.Certificate, 117 Name: "checksum.pem", 118 Path: certpath, 119 Extra: map[string]interface{}{ 120 artifact.ExtraID: "foo", 121 }, 122 }) 123 ctx.Artifacts.Add(&artifact.Artifact{ 124 Type: artifact.UploadableSourceArchive, 125 Name: "source.tar.gz", 126 Path: srcpath, 127 Extra: map[string]interface{}{ 128 artifact.ExtraFormat: "tar.gz", 129 }, 130 }) 131 ctx.Artifacts.Add(&artifact.Artifact{ 132 Type: artifact.UploadableArchive, 133 Name: "bin.tar.gz", 134 Path: tgzpath, 135 Extra: map[string]interface{}{ 136 artifact.ExtraID: "foo", 137 }, 138 }) 139 ctx.Artifacts.Add(&artifact.Artifact{ 140 Type: artifact.LinuxPackage, 141 Name: "bin.deb", 142 Path: debpath, 143 Extra: map[string]interface{}{ 144 artifact.ExtraID: "bar", 145 }, 146 }) 147 148 setupBucket(t, testlib.MustDockerPool(t), name) 149 require.NoError(t, Pipe{}.Default(ctx)) 150 require.NoError(t, Pipe{}.Publish(ctx)) 151 152 require.Subset(t, getFiles(t, ctx, ctx.Config.Blobs[0]), []string{ 153 "testupload/v1.0.0/bin.deb", 154 "testupload/v1.0.0/bin.tar.gz", 155 "testupload/v1.0.0/checksum.txt", 156 "testupload/v1.0.0/checksum.txt.sig", 157 "testupload/v1.0.0/checksum.pem", 158 "testupload/v1.0.0/source.tar.gz", 159 "testupload/v1.0.0/file.golden", 160 }) 161 } 162 163 func TestMinioUploadCustomBucketID(t *testing.T) { 164 name := "fromenv" 165 folder := t.TempDir() 166 tgzpath := filepath.Join(folder, "bin.tar.gz") 167 debpath := filepath.Join(folder, "bin.deb") 168 require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744)) 169 require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744)) 170 // Set custom BUCKET_ID env variable. 171 t.Setenv("BUCKET_ID", name) 172 ctx := testctx.NewWithCfg(config.Project{ 173 Dist: folder, 174 ProjectName: "testupload", 175 Blobs: []config.Blob{ 176 { 177 Provider: "s3", 178 Bucket: "{{.Env.BUCKET_ID}}", 179 Endpoint: "http://" + listen, 180 }, 181 }, 182 }, testctx.WithCurrentTag("v1.0.0")) 183 ctx.Artifacts.Add(&artifact.Artifact{ 184 Type: artifact.UploadableArchive, 185 Name: "bin.tar.gz", 186 Path: tgzpath, 187 }) 188 ctx.Artifacts.Add(&artifact.Artifact{ 189 Type: artifact.LinuxPackage, 190 Name: "bin.deb", 191 Path: debpath, 192 }) 193 194 setupBucket(t, testlib.MustDockerPool(t), name) 195 require.NoError(t, Pipe{}.Default(ctx)) 196 require.NoError(t, Pipe{}.Publish(ctx)) 197 } 198 199 func TestMinioUploadRootFolder(t *testing.T) { 200 name := "rootdir" 201 folder := t.TempDir() 202 tgzpath := filepath.Join(folder, "bin.tar.gz") 203 debpath := filepath.Join(folder, "bin.deb") 204 require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744)) 205 require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744)) 206 ctx := testctx.NewWithCfg(config.Project{ 207 Dist: folder, 208 ProjectName: "testupload", 209 Blobs: []config.Blob{ 210 { 211 Provider: "s3", 212 Bucket: name, 213 Folder: "/", 214 Endpoint: "http://" + listen, 215 }, 216 }, 217 }, testctx.WithCurrentTag("v1.0.0")) 218 ctx.Artifacts.Add(&artifact.Artifact{ 219 Type: artifact.UploadableArchive, 220 Name: "bin.tar.gz", 221 Path: tgzpath, 222 }) 223 ctx.Artifacts.Add(&artifact.Artifact{ 224 Type: artifact.LinuxPackage, 225 Name: "bin.deb", 226 Path: debpath, 227 }) 228 229 setupBucket(t, testlib.MustDockerPool(t), name) 230 require.NoError(t, Pipe{}.Default(ctx)) 231 require.NoError(t, Pipe{}.Publish(ctx)) 232 } 233 234 func TestMinioUploadInvalidCustomBucketID(t *testing.T) { 235 folder := t.TempDir() 236 tgzpath := filepath.Join(folder, "bin.tar.gz") 237 debpath := filepath.Join(folder, "bin.deb") 238 require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744)) 239 require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744)) 240 ctx := testctx.NewWithCfg(config.Project{ 241 Dist: folder, 242 ProjectName: "testupload", 243 Blobs: []config.Blob{ 244 { 245 Provider: "s3", 246 Bucket: "{{.Bad}}", 247 Endpoint: "http://" + listen, 248 }, 249 }, 250 }, testctx.WithCurrentTag("v1.1.0")) 251 ctx.Artifacts.Add(&artifact.Artifact{ 252 Type: artifact.UploadableArchive, 253 Name: "bin.tar.gz", 254 Path: tgzpath, 255 }) 256 ctx.Artifacts.Add(&artifact.Artifact{ 257 Type: artifact.LinuxPackage, 258 Name: "bin.deb", 259 Path: debpath, 260 }) 261 262 require.NoError(t, Pipe{}.Default(ctx)) 263 require.Error(t, Pipe{}.Publish(ctx)) 264 } 265 266 func TestMinioUploadSkip(t *testing.T) { 267 name := "basic" 268 folder := t.TempDir() 269 debpath := filepath.Join(folder, "bin.deb") 270 tgzpath := filepath.Join(folder, "bin.tar.gz") 271 require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744)) 272 require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744)) 273 274 buildCtx := func(uploadID string) *context.Context { 275 ctx := testctx.NewWithCfg( 276 config.Project{ 277 Dist: folder, 278 ProjectName: "testupload", 279 Blobs: []config.Blob{ 280 { 281 Provider: "s3", 282 Bucket: name, 283 Region: "us-east", 284 Endpoint: "http://" + listen, 285 IDs: []string{"foo"}, 286 Disable: `{{ eq .Env.UPLOAD_ID "foo" }}`, 287 }, 288 { 289 Provider: "s3", 290 Bucket: name, 291 Region: "us-east", 292 Endpoint: "http://" + listen, 293 Disable: `{{ eq .Env.UPLOAD_ID "bar" }}`, 294 IDs: []string{"bar"}, 295 }, 296 }, 297 }, 298 testctx.WithCurrentTag("v1.0.0"), 299 testctx.WithEnv(map[string]string{ 300 "UPLOAD_ID": uploadID, 301 }), 302 ) 303 ctx.Artifacts.Add(&artifact.Artifact{ 304 Type: artifact.UploadableArchive, 305 Name: "bin.tar.gz", 306 Path: tgzpath, 307 Extra: map[string]interface{}{ 308 artifact.ExtraID: "foo", 309 }, 310 }) 311 ctx.Artifacts.Add(&artifact.Artifact{ 312 Type: artifact.LinuxPackage, 313 Name: "bin.deb", 314 Path: debpath, 315 Extra: map[string]interface{}{ 316 artifact.ExtraID: "bar", 317 }, 318 }) 319 return ctx 320 } 321 322 setupBucket(t, testlib.MustDockerPool(t), name) 323 324 t.Run("upload only foo", func(t *testing.T) { 325 ctx := buildCtx("foo") 326 require.NoError(t, Pipe{}.Default(ctx)) 327 testlib.AssertSkipped(t, Pipe{}.Publish(ctx)) 328 require.Subset(t, getFiles(t, ctx, ctx.Config.Blobs[0]), []string{ 329 "testupload/v1.0.0/bin.deb", 330 }) 331 }) 332 333 t.Run("upload only bar", func(t *testing.T) { 334 ctx := buildCtx("bar") 335 require.NoError(t, Pipe{}.Default(ctx)) 336 testlib.AssertSkipped(t, Pipe{}.Publish(ctx)) 337 require.Subset(t, getFiles(t, ctx, ctx.Config.Blobs[0]), []string{ 338 "testupload/v1.0.0/bin.tar.gz", 339 }) 340 }) 341 342 t.Run("invalid tmpl", func(t *testing.T) { 343 ctx := buildCtx("none") 344 ctx.Config.Blobs = []config.Blob{{ 345 Provider: "s3", 346 Bucket: name, 347 Endpoint: "http://" + listen, 348 Disable: `{{ .Env.NOME }}`, 349 }} 350 require.NoError(t, Pipe{}.Default(ctx)) 351 testlib.RequireTemplateError(t, Pipe{}.Publish(ctx)) 352 }) 353 } 354 355 func prepareEnv() { 356 os.Setenv("AWS_ACCESS_KEY_ID", minioUser) 357 os.Setenv("AWS_SECRET_ACCESS_KEY", minioPwd) 358 os.Setenv("AWS_REGION", "us-east-1") 359 } 360 361 func setupBucket(tb testing.TB, pool *dockertest.Pool, name string) { 362 tb.Helper() 363 364 res, err := pool.RunWithOptions(&dockertest.RunOptions{ 365 Repository: "minio/mc", 366 Links: []string{containerName}, 367 Env: []string{fmt.Sprintf("MC_HOST_local=http://%s:%s@%s:9000", minioUser, minioPwd, containerName)}, 368 Cmd: []string{"mb", "local/" + name}, 369 }, func(hc *docker.HostConfig) { 370 hc.AutoRemove = true 371 }) 372 require.NoError(tb, err) 373 require.NoError(tb, pool.Retry(func() error { 374 if _, ok := pool.ContainerByName(res.Container.Name); ok { 375 return fmt.Errorf("still running: %s", res.Container.Name) 376 } 377 return nil 378 })) 379 } 380 381 func getFiles(t *testing.T, ctx *context.Context, cfg config.Blob) []string { 382 t.Helper() 383 url, err := urlFor(ctx, cfg) 384 require.NoError(t, err) 385 conn, err := blob.OpenBucket(ctx, url) 386 require.NoError(t, err) 387 defer conn.Close() 388 iter := conn.List(nil) 389 var files []string 390 for { 391 file, err := iter.Next(ctx) 392 if err != nil && err == io.EOF { 393 break 394 } 395 require.NoError(t, err) 396 files = append(files, file.Key) 397 } 398 return files 399 }