gopkg.in/goreleaser/goreleaser.v0@v0.92.0/internal/pipe/put/put_test.go (about)

     1  package put
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"path/filepath"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/goreleaser/goreleaser/internal/artifact"
    14  	"github.com/goreleaser/goreleaser/internal/pipe"
    15  	"github.com/goreleaser/goreleaser/pkg/config"
    16  	"github.com/goreleaser/goreleaser/pkg/context"
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  var (
    21  	// mux is the HTTP request multiplexer used with the test server.
    22  	mux *http.ServeMux
    23  
    24  	// server is a test HTTP server used to provide mock API responses.
    25  	server *httptest.Server
    26  )
    27  
    28  func setup() {
    29  	// test server
    30  	mux = http.NewServeMux()
    31  	server = httptest.NewServer(mux)
    32  }
    33  
    34  // teardown closes the test HTTP server.
    35  func teardown() {
    36  	server.Close()
    37  }
    38  
    39  func testMethod(t *testing.T, r *http.Request, want string) {
    40  	if got := r.Method; got != want {
    41  		t.Errorf("Request method: %v, want %v", got, want)
    42  	}
    43  }
    44  
    45  func testHeader(t *testing.T, r *http.Request, header string, want string) {
    46  	if got := r.Header.Get(header); got != want {
    47  		t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want)
    48  	}
    49  }
    50  
    51  // TODO: improve all tests bellow by checking wether the mocked handlers
    52  // were called or not.
    53  
    54  func TestRunPipe_ModeBinary(t *testing.T) {
    55  	setup()
    56  	defer teardown()
    57  
    58  	folder, err := ioutil.TempDir("", "archivetest")
    59  	assert.NoError(t, err)
    60  	var dist = filepath.Join(folder, "dist")
    61  	assert.NoError(t, os.Mkdir(dist, 0755))
    62  	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
    63  	var binPath = filepath.Join(dist, "mybin", "mybin")
    64  	d1 := []byte("hello\ngo\n")
    65  	err = ioutil.WriteFile(binPath, d1, 0666)
    66  	assert.NoError(t, err)
    67  
    68  	// Dummy http server
    69  	mux.HandleFunc("/example-repo-local/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    70  		testMethod(t, r, "PUT")
    71  		testHeader(t, r, "Content-Length", "9")
    72  		// Basic auth of user "deployuser" with secret "deployuser-secret"
    73  		testHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
    74  
    75  		w.Header().Set("Location", "/production-repo-remote/mybin/linux/amd64/mybin")
    76  		w.WriteHeader(http.StatusCreated)
    77  	})
    78  	mux.HandleFunc("/example-repo-local/mybin/linux/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    79  		testMethod(t, r, "PUT")
    80  		testHeader(t, r, "Content-Length", "9")
    81  		// Basic auth of user "deployuser" with secret "deployuser-secret"
    82  		testHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
    83  
    84  		w.Header().Set("Location", "/production-repo-remote/mybin/linux/amd64/mybin")
    85  		w.WriteHeader(http.StatusCreated)
    86  	})
    87  	mux.HandleFunc("/production-repo-remote/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    88  		testMethod(t, r, "PUT")
    89  		testHeader(t, r, "Content-Length", "9")
    90  		// Basic auth of user "productionuser" with secret "productionuser-apikey"
    91  		testHeader(t, r, "Authorization", "Basic cHJvZHVjdGlvbnVzZXI6cHJvZHVjdGlvbnVzZXItYXBpa2V5")
    92  
    93  		w.Header().Set("Location", "/production-repo-remote/mybin/linux/amd64/mybin")
    94  		w.WriteHeader(http.StatusCreated)
    95  	})
    96  	mux.HandleFunc("/production-repo-remote/mybin/linux/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    97  		testMethod(t, r, "PUT")
    98  		testHeader(t, r, "Content-Length", "9")
    99  		// Basic auth of user "productionuser" with secret "productionuser-apikey"
   100  		testHeader(t, r, "Authorization", "Basic cHJvZHVjdGlvbnVzZXI6cHJvZHVjdGlvbnVzZXItYXBpa2V5")
   101  
   102  		w.Header().Set("Location", "/production-repo-remote/mybin/linux/amd64/mybin")
   103  		w.WriteHeader(http.StatusCreated)
   104  	})
   105  
   106  	var ctx = context.New(config.Project{
   107  		ProjectName: "mybin",
   108  		Dist:        dist,
   109  		Puts: []config.Put{
   110  			{
   111  				Name:     "production-us",
   112  				Mode:     "binary",
   113  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   114  				Username: "deployuser",
   115  			},
   116  			{
   117  				Name:     "production-eu",
   118  				Mode:     "binary",
   119  				Target:   fmt.Sprintf("%s/production-repo-remote/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   120  				Username: "productionuser",
   121  			},
   122  		},
   123  	})
   124  	ctx.Env = map[string]string{
   125  		"PUT_PRODUCTION-US_SECRET": "deployuser-secret",
   126  		"PUT_PRODUCTION-EU_SECRET": "productionuser-apikey",
   127  	}
   128  	for _, goos := range []string{"linux", "darwin"} {
   129  		ctx.Artifacts.Add(artifact.Artifact{
   130  			Name:   "mybin",
   131  			Path:   binPath,
   132  			Goarch: "amd64",
   133  			Goos:   goos,
   134  			Type:   artifact.UploadableBinary,
   135  		})
   136  	}
   137  
   138  	assert.NoError(t, Pipe{}.Publish(ctx))
   139  }
   140  
   141  func TestRunPipe_ModeArchive(t *testing.T) {
   142  	setup()
   143  	defer teardown()
   144  
   145  	folder, err := ioutil.TempDir("", "goreleasertest")
   146  	assert.NoError(t, err)
   147  	tarfile, err := os.Create(filepath.Join(folder, "bin.tar.gz"))
   148  	assert.NoError(t, err)
   149  	debfile, err := os.Create(filepath.Join(folder, "bin.deb"))
   150  	assert.NoError(t, err)
   151  
   152  	var ctx = context.New(config.Project{
   153  		ProjectName: "goreleaser",
   154  		Dist:        folder,
   155  		Puts: []config.Put{
   156  			{
   157  				Name:     "production",
   158  				Mode:     "archive",
   159  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Version }}/", server.URL),
   160  				Username: "deployuser",
   161  			},
   162  		},
   163  	})
   164  	ctx.Env = map[string]string{
   165  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   166  	}
   167  	ctx.Version = "1.0.0"
   168  	ctx.Artifacts.Add(artifact.Artifact{
   169  		Type: artifact.UploadableArchive,
   170  		Name: "bin.tar.gz",
   171  		Path: tarfile.Name(),
   172  	})
   173  	ctx.Artifacts.Add(artifact.Artifact{
   174  		Type: artifact.LinuxPackage,
   175  		Name: "bin.deb",
   176  		Path: debfile.Name(),
   177  	})
   178  
   179  	var uploads sync.Map
   180  
   181  	// Dummy http server
   182  	mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.tar.gz", func(w http.ResponseWriter, r *http.Request) {
   183  		testMethod(t, r, "PUT")
   184  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   185  		testHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   186  
   187  		w.Header().Set("Location", "/example-repo-local/goreleaser/1.0.0/bin.tar.gz")
   188  		w.WriteHeader(http.StatusCreated)
   189  		uploads.Store("targz", true)
   190  	})
   191  	mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.deb", func(w http.ResponseWriter, r *http.Request) {
   192  		testMethod(t, r, "PUT")
   193  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   194  		testHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   195  
   196  		w.Header().Set("Location", "/example-repo-local/goreleaser/1.0.0/bin.deb")
   197  		w.WriteHeader(http.StatusCreated)
   198  		uploads.Store("deb", true)
   199  	})
   200  
   201  	assert.NoError(t, Pipe{}.Publish(ctx))
   202  	_, ok := uploads.Load("targz")
   203  	assert.True(t, ok, "tar.gz file was not uploaded")
   204  	_, ok = uploads.Load("deb")
   205  	assert.True(t, ok, "deb file was not uploaded")
   206  }
   207  
   208  func TestRunPipe_ArtifactoryDown(t *testing.T) {
   209  	folder, err := ioutil.TempDir("", "goreleasertest")
   210  	assert.NoError(t, err)
   211  	tarfile, err := os.Create(filepath.Join(folder, "bin.tar.gz"))
   212  	assert.NoError(t, err)
   213  
   214  	var ctx = context.New(config.Project{
   215  		ProjectName: "goreleaser",
   216  		Dist:        folder,
   217  		Puts: []config.Put{
   218  			{
   219  				Name:     "production",
   220  				Mode:     "archive",
   221  				Target:   "http://localhost:1234/example-repo-local/{{ .ProjectName }}/{{ .Version }}/",
   222  				Username: "deployuser",
   223  			},
   224  		},
   225  	})
   226  	ctx.Version = "2.0.0"
   227  	ctx.Env = map[string]string{
   228  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   229  	}
   230  	ctx.Artifacts.Add(artifact.Artifact{
   231  		Type: artifact.UploadableArchive,
   232  		Name: "bin.tar.gz",
   233  		Path: tarfile.Name(),
   234  	})
   235  	err = Pipe{}.Publish(ctx)
   236  	assert.Error(t, err)
   237  	assert.Contains(t, err.Error(), "connection refused")
   238  }
   239  
   240  func TestRunPipe_TargetTemplateError(t *testing.T) {
   241  	folder, err := ioutil.TempDir("", "archivetest")
   242  	assert.NoError(t, err)
   243  	var dist = filepath.Join(folder, "dist")
   244  	var binPath = filepath.Join(dist, "mybin", "mybin")
   245  
   246  	var ctx = context.New(config.Project{
   247  		ProjectName: "mybin",
   248  		Dist:        dist,
   249  		Puts: []config.Put{
   250  			{
   251  				Name: "production",
   252  				Mode: "binary",
   253  				// This template is not correct and should fail
   254  				Target:   "http://storage.company.com/example-repo-local/{{ .ProjectName /{{ .Version }}/",
   255  				Username: "deployuser",
   256  			},
   257  		},
   258  	})
   259  	ctx.Env = map[string]string{
   260  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   261  	}
   262  	ctx.Artifacts.Add(artifact.Artifact{
   263  		Name:   "mybin",
   264  		Path:   binPath,
   265  		Goarch: "amd64",
   266  		Goos:   "darwin",
   267  		Type:   artifact.UploadableBinary,
   268  	})
   269  	err = Pipe{}.Publish(ctx)
   270  	assert.Error(t, err)
   271  	assert.Contains(t, err.Error(), `put: error while building the target url: template: mybin:1: unexpected "/" in operand`)
   272  }
   273  
   274  func TestRunPipe_BadCredentials(t *testing.T) {
   275  	setup()
   276  	defer teardown()
   277  
   278  	folder, err := ioutil.TempDir("", "archivetest")
   279  	assert.NoError(t, err)
   280  	var dist = filepath.Join(folder, "dist")
   281  	assert.NoError(t, os.Mkdir(dist, 0755))
   282  	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
   283  	var binPath = filepath.Join(dist, "mybin", "mybin")
   284  	d1 := []byte("hello\ngo\n")
   285  	err = ioutil.WriteFile(binPath, d1, 0666)
   286  	assert.NoError(t, err)
   287  
   288  	// Dummy http server
   289  	mux.HandleFunc("/example-repo-local/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
   290  		testMethod(t, r, "PUT")
   291  		testHeader(t, r, "Content-Length", "9")
   292  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   293  		testHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   294  
   295  		w.WriteHeader(http.StatusUnauthorized)
   296  	})
   297  
   298  	var ctx = context.New(config.Project{
   299  		ProjectName: "mybin",
   300  		Dist:        dist,
   301  		Puts: []config.Put{
   302  			{
   303  				Name:     "production",
   304  				Mode:     "binary",
   305  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   306  				Username: "deployuser",
   307  			},
   308  		},
   309  	})
   310  	ctx.Env = map[string]string{
   311  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   312  	}
   313  	ctx.Artifacts.Add(artifact.Artifact{
   314  		Name:   "mybin",
   315  		Path:   binPath,
   316  		Goarch: "amd64",
   317  		Goos:   "darwin",
   318  		Type:   artifact.UploadableBinary,
   319  	})
   320  
   321  	err = Pipe{}.Publish(ctx)
   322  	assert.Error(t, err)
   323  	assert.Contains(t, err.Error(), "Unauthorized")
   324  }
   325  
   326  func TestRunPipe_FileNotFound(t *testing.T) {
   327  	var ctx = context.New(config.Project{
   328  		ProjectName: "mybin",
   329  		Dist:        "archivetest/dist",
   330  		Puts: []config.Put{
   331  			{
   332  				Name:     "production",
   333  				Mode:     "binary",
   334  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   335  				Username: "deployuser",
   336  			},
   337  		},
   338  	})
   339  	ctx.Env = map[string]string{
   340  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   341  	}
   342  	ctx.Artifacts.Add(artifact.Artifact{
   343  		Name:   "mybin",
   344  		Path:   "archivetest/dist/mybin/mybin",
   345  		Goarch: "amd64",
   346  		Goos:   "darwin",
   347  		Type:   artifact.UploadableBinary,
   348  	})
   349  
   350  	assert.EqualError(t, Pipe{}.Publish(ctx), `open archivetest/dist/mybin/mybin: no such file or directory`)
   351  }
   352  
   353  func TestRunPipe_UnparsableTarget(t *testing.T) {
   354  	folder, err := ioutil.TempDir("", "archivetest")
   355  	assert.NoError(t, err)
   356  	var dist = filepath.Join(folder, "dist")
   357  	assert.NoError(t, os.Mkdir(dist, 0755))
   358  	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
   359  	var binPath = filepath.Join(dist, "mybin", "mybin")
   360  	d1 := []byte("hello\ngo\n")
   361  	err = ioutil.WriteFile(binPath, d1, 0666)
   362  	assert.NoError(t, err)
   363  
   364  	var ctx = context.New(config.Project{
   365  		ProjectName: "mybin",
   366  		Dist:        dist,
   367  		Puts: []config.Put{
   368  			{
   369  				Name:     "production",
   370  				Mode:     "binary",
   371  				Target:   "://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   372  				Username: "deployuser",
   373  			},
   374  		},
   375  	})
   376  	ctx.Env = map[string]string{
   377  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   378  	}
   379  	ctx.Artifacts.Add(artifact.Artifact{
   380  		Name:   "mybin",
   381  		Path:   binPath,
   382  		Goarch: "amd64",
   383  		Goos:   "darwin",
   384  		Type:   artifact.UploadableBinary,
   385  	})
   386  
   387  	assert.EqualError(t, Pipe{}.Publish(ctx), `put: upload failed: parse ://artifacts.company.com/example-repo-local/mybin/darwin/amd64/mybin: missing protocol scheme`)
   388  }
   389  
   390  func TestRunPipe_SkipWhenPublishFalse(t *testing.T) {
   391  	var ctx = context.New(config.Project{
   392  		Puts: []config.Put{
   393  			{
   394  				Name:     "production",
   395  				Mode:     "binary",
   396  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   397  				Username: "deployuser",
   398  			},
   399  		},
   400  	})
   401  	ctx.Env = map[string]string{
   402  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   403  	}
   404  	ctx.SkipPublish = true
   405  
   406  	err := Pipe{}.Publish(ctx)
   407  	assert.True(t, pipe.IsSkip(err))
   408  	assert.EqualError(t, err, pipe.ErrSkipPublishEnabled.Error())
   409  }
   410  
   411  func TestRunPipe_DirUpload(t *testing.T) {
   412  	folder, err := ioutil.TempDir("", "archivetest")
   413  	assert.NoError(t, err)
   414  	var dist = filepath.Join(folder, "dist")
   415  	assert.NoError(t, os.Mkdir(dist, 0755))
   416  	assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
   417  	var binPath = filepath.Join(dist, "mybin")
   418  
   419  	var ctx = context.New(config.Project{
   420  		ProjectName: "mybin",
   421  		Dist:        dist,
   422  		Puts: []config.Put{
   423  			{
   424  				Name:     "production",
   425  				Mode:     "binary",
   426  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   427  				Username: "deployuser",
   428  			},
   429  		},
   430  	})
   431  	ctx.Env = map[string]string{
   432  		"PUT_PRODUCTION_SECRET": "deployuser-secret",
   433  	}
   434  	ctx.Artifacts.Add(artifact.Artifact{
   435  		Name:   "mybin",
   436  		Path:   filepath.Dir(binPath),
   437  		Goarch: "amd64",
   438  		Goos:   "darwin",
   439  		Type:   artifact.UploadableBinary,
   440  	})
   441  
   442  	assert.EqualError(t, Pipe{}.Publish(ctx), `put: upload failed: the asset to upload can't be a directory`)
   443  }
   444  
   445  func TestDescription(t *testing.T) {
   446  	assert.NotEmpty(t, Pipe{}.String())
   447  }
   448  
   449  func TestNoPuts(t *testing.T) {
   450  	assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{}))))
   451  }
   452  
   453  func TestPutsWithoutTarget(t *testing.T) {
   454  	var ctx = &context.Context{
   455  		Env: map[string]string{
   456  			"PUT_PRODUCTION_SECRET": "deployuser-secret",
   457  		},
   458  		Config: config.Project{
   459  			Puts: []config.Put{
   460  				{
   461  					Name:     "production",
   462  					Username: "deployuser",
   463  				},
   464  			},
   465  		},
   466  	}
   467  
   468  	assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx)))
   469  }
   470  
   471  func TestPutsWithoutUsername(t *testing.T) {
   472  	var ctx = &context.Context{
   473  		Env: map[string]string{
   474  			"PUT_PRODUCTION_SECRET": "deployuser-secret",
   475  		},
   476  		Config: config.Project{
   477  			Puts: []config.Put{
   478  				{
   479  					Name:   "production",
   480  					Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   481  				},
   482  			},
   483  		},
   484  	}
   485  
   486  	assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx)))
   487  }
   488  
   489  func TestPutsWithoutName(t *testing.T) {
   490  	assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{
   491  		Puts: []config.Put{
   492  			{
   493  				Username: "deployuser",
   494  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   495  			},
   496  		},
   497  	}))))
   498  }
   499  
   500  func TestPutsWithoutSecret(t *testing.T) {
   501  	assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{
   502  		Puts: []config.Put{
   503  			{
   504  				Name:     "production",
   505  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   506  				Username: "deployuser",
   507  			},
   508  		},
   509  	}))))
   510  }
   511  
   512  func TestPutsWithInvalidMode(t *testing.T) {
   513  	var ctx = &context.Context{
   514  		Env: map[string]string{
   515  			"PUT_PRODUCTION_SECRET": "deployuser-secret",
   516  		},
   517  		Config: config.Project{
   518  			Puts: []config.Put{
   519  				{
   520  					Name:     "production",
   521  					Mode:     "does-not-exists",
   522  					Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   523  					Username: "deployuser",
   524  				},
   525  			},
   526  		},
   527  	}
   528  	assert.Error(t, Pipe{}.Publish(ctx))
   529  }
   530  
   531  func TestDefault(t *testing.T) {
   532  	var ctx = &context.Context{
   533  		Config: config.Project{
   534  			Puts: []config.Put{
   535  				{
   536  					Name:     "production",
   537  					Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   538  					Username: "deployuser",
   539  				},
   540  			},
   541  		},
   542  	}
   543  	assert.NoError(t, Pipe{}.Default(ctx))
   544  	assert.Len(t, ctx.Config.Puts, 1)
   545  	var put = ctx.Config.Puts[0]
   546  	assert.Equal(t, "archive", put.Mode)
   547  }
   548  
   549  func TestDefaultNoPuts(t *testing.T) {
   550  	var ctx = &context.Context{
   551  		Config: config.Project{
   552  			Puts: []config.Put{},
   553  		},
   554  	}
   555  	assert.NoError(t, Pipe{}.Default(ctx))
   556  	assert.Empty(t, ctx.Config.Puts)
   557  }
   558  
   559  func TestDefaultSet(t *testing.T) {
   560  	var ctx = &context.Context{
   561  		Config: config.Project{
   562  			Puts: []config.Put{
   563  				{
   564  					Mode: "custom",
   565  				},
   566  			},
   567  		},
   568  	}
   569  	assert.NoError(t, Pipe{}.Default(ctx))
   570  	assert.Len(t, ctx.Config.Puts, 1)
   571  	var put = ctx.Config.Puts[0]
   572  	assert.Equal(t, "custom", put.Mode)
   573  }