github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/blob/blob_minio_test.go (about)

     1  package blob
     2  
     3  // this is pretty much copied from the s3 pipe to ensure both work the same way
     4  // only differences are that it sets `blobs` instead of `s3` on test cases and
     5  // the test setup and teardown
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/goreleaser/goreleaser/internal/artifact"
    19  	"github.com/goreleaser/goreleaser/pkg/config"
    20  	"github.com/goreleaser/goreleaser/pkg/context"
    21  	"github.com/stretchr/testify/require"
    22  	"gocloud.dev/blob"
    23  )
    24  
    25  const (
    26  	minioUser = "minio"
    27  	minioPwd  = "miniostorage"
    28  )
    29  
    30  func TestMinioUpload(t *testing.T) {
    31  	listen := randomListen(t)
    32  	folder := t.TempDir()
    33  	srcpath := filepath.Join(folder, "source.tar.gz")
    34  	tgzpath := filepath.Join(folder, "bin.tar.gz")
    35  	debpath := filepath.Join(folder, "bin.deb")
    36  	checkpath := filepath.Join(folder, "check.txt")
    37  	require.NoError(t, os.WriteFile(checkpath, []byte("fake checksums"), 0o744))
    38  	require.NoError(t, os.WriteFile(srcpath, []byte("fake\nsrc"), 0o744))
    39  	require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
    40  	require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
    41  	ctx := context.New(config.Project{
    42  		Dist:        folder,
    43  		ProjectName: "testupload",
    44  		Blobs: []config.Blob{
    45  			{
    46  				Provider: "s3",
    47  				Bucket:   "test",
    48  				Region:   "us-east",
    49  				Endpoint: "http://" + listen,
    50  				IDs:      []string{"foo", "bar"},
    51  			},
    52  		},
    53  	})
    54  	ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
    55  	ctx.Artifacts.Add(&artifact.Artifact{
    56  		Type: artifact.Checksum,
    57  		Name: "checksum.txt",
    58  		Path: checkpath,
    59  	})
    60  	ctx.Artifacts.Add(&artifact.Artifact{
    61  		Type: artifact.UploadableSourceArchive,
    62  		Name: "source.tar.gz",
    63  		Path: srcpath,
    64  		Extra: map[string]interface{}{
    65  			"Format": "tar.gz",
    66  		},
    67  	})
    68  	ctx.Artifacts.Add(&artifact.Artifact{
    69  		Type: artifact.UploadableArchive,
    70  		Name: "bin.tar.gz",
    71  		Path: tgzpath,
    72  		Extra: map[string]interface{}{
    73  			"ID": "foo",
    74  		},
    75  	})
    76  	ctx.Artifacts.Add(&artifact.Artifact{
    77  		Type: artifact.LinuxPackage,
    78  		Name: "bin.deb",
    79  		Path: debpath,
    80  		Extra: map[string]interface{}{
    81  			"ID": "bar",
    82  		},
    83  	})
    84  	name := "test_upload"
    85  	start(t, name, listen)
    86  	prepareEnv()
    87  	require.NoError(t, Pipe{}.Default(ctx))
    88  	require.NoError(t, Pipe{}.Publish(ctx))
    89  
    90  	require.Subset(t, getFiles(t, ctx, ctx.Config.Blobs[0]), []string{
    91  		"testupload/v1.0.0/bin.deb",
    92  		"testupload/v1.0.0/bin.tar.gz",
    93  		"testupload/v1.0.0/checksum.txt",
    94  		"testupload/v1.0.0/source.tar.gz",
    95  	})
    96  }
    97  
    98  func TestMinioUploadCustomBucketID(t *testing.T) {
    99  	listen := randomListen(t)
   100  	folder := t.TempDir()
   101  	tgzpath := filepath.Join(folder, "bin.tar.gz")
   102  	debpath := filepath.Join(folder, "bin.deb")
   103  	require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
   104  	require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
   105  	// Set custom BUCKET_ID env variable.
   106  	require.NoError(t, os.Setenv("BUCKET_ID", "test"))
   107  	ctx := context.New(config.Project{
   108  		Dist:        folder,
   109  		ProjectName: "testupload",
   110  		Blobs: []config.Blob{
   111  			{
   112  				Provider: "s3",
   113  				Bucket:   "{{.Env.BUCKET_ID}}",
   114  				Endpoint: "http://" + listen,
   115  			},
   116  		},
   117  	})
   118  	ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
   119  	ctx.Artifacts.Add(&artifact.Artifact{
   120  		Type: artifact.UploadableArchive,
   121  		Name: "bin.tar.gz",
   122  		Path: tgzpath,
   123  	})
   124  	ctx.Artifacts.Add(&artifact.Artifact{
   125  		Type: artifact.LinuxPackage,
   126  		Name: "bin.deb",
   127  		Path: debpath,
   128  	})
   129  	name := "custom_bucket_id"
   130  	start(t, name, listen)
   131  	prepareEnv()
   132  	require.NoError(t, Pipe{}.Default(ctx))
   133  	require.NoError(t, Pipe{}.Publish(ctx))
   134  }
   135  
   136  func TestMinioUploadRootFolder(t *testing.T) {
   137  	listen := randomListen(t)
   138  	folder := t.TempDir()
   139  	tgzpath := filepath.Join(folder, "bin.tar.gz")
   140  	debpath := filepath.Join(folder, "bin.deb")
   141  	require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
   142  	require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
   143  	ctx := context.New(config.Project{
   144  		Dist:        folder,
   145  		ProjectName: "testupload",
   146  		Blobs: []config.Blob{
   147  			{
   148  				Provider: "s3",
   149  				Bucket:   "test",
   150  				Folder:   "/",
   151  				Endpoint: "http://" + listen,
   152  			},
   153  		},
   154  	})
   155  	ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
   156  	ctx.Artifacts.Add(&artifact.Artifact{
   157  		Type: artifact.UploadableArchive,
   158  		Name: "bin.tar.gz",
   159  		Path: tgzpath,
   160  	})
   161  	ctx.Artifacts.Add(&artifact.Artifact{
   162  		Type: artifact.LinuxPackage,
   163  		Name: "bin.deb",
   164  		Path: debpath,
   165  	})
   166  	name := "root_folder"
   167  	start(t, name, listen)
   168  	prepareEnv()
   169  	require.NoError(t, Pipe{}.Default(ctx))
   170  	require.NoError(t, Pipe{}.Publish(ctx))
   171  }
   172  
   173  func TestMinioUploadInvalidCustomBucketID(t *testing.T) {
   174  	listen := randomListen(t)
   175  	folder := t.TempDir()
   176  	tgzpath := filepath.Join(folder, "bin.tar.gz")
   177  	debpath := filepath.Join(folder, "bin.deb")
   178  	require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
   179  	require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
   180  	ctx := context.New(config.Project{
   181  		Dist:        folder,
   182  		ProjectName: "testupload",
   183  		Blobs: []config.Blob{
   184  			{
   185  				Provider: "s3",
   186  				Bucket:   "{{.Bad}}",
   187  				Endpoint: "http://" + listen,
   188  			},
   189  		},
   190  	})
   191  	ctx.Git = context.GitInfo{CurrentTag: "v1.1.0"}
   192  	ctx.Artifacts.Add(&artifact.Artifact{
   193  		Type: artifact.UploadableArchive,
   194  		Name: "bin.tar.gz",
   195  		Path: tgzpath,
   196  	})
   197  	ctx.Artifacts.Add(&artifact.Artifact{
   198  		Type: artifact.LinuxPackage,
   199  		Name: "bin.deb",
   200  		Path: debpath,
   201  	})
   202  	name := "invalid_bucket_id"
   203  	start(t, name, listen)
   204  	prepareEnv()
   205  	require.NoError(t, Pipe{}.Default(ctx))
   206  	require.Error(t, Pipe{}.Publish(ctx))
   207  }
   208  
   209  func randomListen(t *testing.T) string {
   210  	t.Helper()
   211  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   212  	require.NoError(t, err)
   213  	listener.Close()
   214  	return listener.Addr().String()
   215  }
   216  
   217  func prepareEnv() {
   218  	os.Setenv("AWS_ACCESS_KEY_ID", minioUser)
   219  	os.Setenv("AWS_SECRET_ACCESS_KEY", minioPwd)
   220  	os.Setenv("AWS_REGION", "us-east-1")
   221  }
   222  
   223  func start(tb testing.TB, name, listen string) {
   224  	tb.Helper()
   225  
   226  	data := filepath.Join(os.TempDir(), name)
   227  	tb.Cleanup(func() {
   228  		mc(tb, name, "mc rb --force local/test")
   229  		if out, err := exec.Command("docker", "stop", name).CombinedOutput(); err != nil {
   230  			tb.Fatalf("failed to stop minio: %s", string(out))
   231  		}
   232  		if err := os.RemoveAll(data); err != nil {
   233  			tb.Logf("failed to remove %s", data)
   234  		}
   235  	})
   236  
   237  	if out, err := exec.Command(
   238  		"docker", "run", "-d", "--rm",
   239  		"-v", data+":/data",
   240  		"--name", name,
   241  		"-p", listen+":9000",
   242  		"-e", "MINIO_ROOT_USER="+minioUser,
   243  		"-e", "MINIO_ROOT_PASSWORD="+minioPwd,
   244  		"--health-interval", "1s",
   245  		"--health-cmd=curl --silent --fail http://localhost:9000/minio/health/ready || exit 1",
   246  		"minio/minio",
   247  		"server", "/data", "--console-address", ":9001",
   248  	).CombinedOutput(); err != nil {
   249  		tb.Fatalf("failed to start minio: %s", string(out))
   250  	}
   251  
   252  	for range time.Tick(time.Second) {
   253  		out, err := exec.Command("docker", "inspect", "--format='{{json .State.Health}}'", name).CombinedOutput()
   254  		if err != nil {
   255  			tb.Fatalf("failed to check minio status: %s", string(out))
   256  		}
   257  		if strings.Contains(string(out), `"Status":"healthy"`) {
   258  			tb.Log("minio is healthy")
   259  			break
   260  		}
   261  		tb.Log("waiting for minio to be healthy")
   262  	}
   263  
   264  	mc(tb, name, "mc mb local/test")
   265  }
   266  
   267  func mc(tb testing.TB, name, cmd string) {
   268  	tb.Helper()
   269  
   270  	if out, err := exec.Command(
   271  		"docker", "run", "--rm",
   272  		"--link", name,
   273  		"--entrypoint", "sh",
   274  		"minio/mc",
   275  		"-c", fmt.Sprintf(
   276  			"mc config host add local http://%s:9000 %s %s; %s",
   277  			name, minioUser, minioPwd, cmd,
   278  		),
   279  	).CombinedOutput(); err != nil {
   280  		tb.Fatalf("failed to create test bucket: %s", string(out))
   281  	}
   282  }
   283  
   284  func getFiles(t *testing.T, ctx *context.Context, cfg config.Blob) []string {
   285  	t.Helper()
   286  	url, err := urlFor(ctx, cfg)
   287  	require.NoError(t, err)
   288  	conn, err := blob.OpenBucket(ctx, url)
   289  	require.NoError(t, err)
   290  	defer conn.Close()
   291  	iter := conn.List(nil)
   292  	var files []string
   293  	for {
   294  		file, err := iter.Next(ctx)
   295  		if err != nil && err == io.EOF {
   296  			break
   297  		}
   298  		require.NoError(t, err)
   299  		files = append(files, file.Key)
   300  	}
   301  	return files
   302  }