github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/release/download/download_test.go (about)

     1  package download
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/cli/cli/internal/ghrepo"
    12  	"github.com/cli/cli/pkg/cmdutil"
    13  	"github.com/cli/cli/pkg/httpmock"
    14  	"github.com/cli/cli/pkg/iostreams"
    15  	"github.com/google/shlex"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func Test_NewCmdDownload(t *testing.T) {
    21  	tests := []struct {
    22  		name    string
    23  		args    string
    24  		isTTY   bool
    25  		want    DownloadOptions
    26  		wantErr string
    27  	}{
    28  		{
    29  			name:  "version argument",
    30  			args:  "v1.2.3",
    31  			isTTY: true,
    32  			want: DownloadOptions{
    33  				TagName:      "v1.2.3",
    34  				FilePatterns: []string(nil),
    35  				Destination:  ".",
    36  				Concurrency:  5,
    37  			},
    38  		},
    39  		{
    40  			name:  "version and file pattern",
    41  			args:  "v1.2.3 -p *.tgz",
    42  			isTTY: true,
    43  			want: DownloadOptions{
    44  				TagName:      "v1.2.3",
    45  				FilePatterns: []string{"*.tgz"},
    46  				Destination:  ".",
    47  				Concurrency:  5,
    48  			},
    49  		},
    50  		{
    51  			name:  "multiple file patterns",
    52  			args:  "v1.2.3 -p 1 -p 2,3",
    53  			isTTY: true,
    54  			want: DownloadOptions{
    55  				TagName:      "v1.2.3",
    56  				FilePatterns: []string{"1", "2,3"},
    57  				Destination:  ".",
    58  				Concurrency:  5,
    59  			},
    60  		},
    61  		{
    62  			name:  "version and destination",
    63  			args:  "v1.2.3 -D tmp/assets",
    64  			isTTY: true,
    65  			want: DownloadOptions{
    66  				TagName:      "v1.2.3",
    67  				FilePatterns: []string(nil),
    68  				Destination:  "tmp/assets",
    69  				Concurrency:  5,
    70  			},
    71  		},
    72  		{
    73  			name:  "download latest",
    74  			args:  "-p *",
    75  			isTTY: true,
    76  			want: DownloadOptions{
    77  				TagName:      "",
    78  				FilePatterns: []string{"*"},
    79  				Destination:  ".",
    80  				Concurrency:  5,
    81  			},
    82  		},
    83  		{
    84  			name:    "no arguments",
    85  			args:    "",
    86  			isTTY:   true,
    87  			wantErr: "the '--pattern' flag is required when downloading the latest release",
    88  		},
    89  	}
    90  	for _, tt := range tests {
    91  		t.Run(tt.name, func(t *testing.T) {
    92  			io, _, _, _ := iostreams.Test()
    93  			io.SetStdoutTTY(tt.isTTY)
    94  			io.SetStdinTTY(tt.isTTY)
    95  			io.SetStderrTTY(tt.isTTY)
    96  
    97  			f := &cmdutil.Factory{
    98  				IOStreams: io,
    99  			}
   100  
   101  			var opts *DownloadOptions
   102  			cmd := NewCmdDownload(f, func(o *DownloadOptions) error {
   103  				opts = o
   104  				return nil
   105  			})
   106  			cmd.PersistentFlags().StringP("repo", "R", "", "")
   107  
   108  			argv, err := shlex.Split(tt.args)
   109  			require.NoError(t, err)
   110  			cmd.SetArgs(argv)
   111  
   112  			cmd.SetIn(&bytes.Buffer{})
   113  			cmd.SetOut(ioutil.Discard)
   114  			cmd.SetErr(ioutil.Discard)
   115  
   116  			_, err = cmd.ExecuteC()
   117  			if tt.wantErr != "" {
   118  				require.EqualError(t, err, tt.wantErr)
   119  				return
   120  			} else {
   121  				require.NoError(t, err)
   122  			}
   123  
   124  			assert.Equal(t, tt.want.TagName, opts.TagName)
   125  			assert.Equal(t, tt.want.FilePatterns, opts.FilePatterns)
   126  			assert.Equal(t, tt.want.Destination, opts.Destination)
   127  			assert.Equal(t, tt.want.Concurrency, opts.Concurrency)
   128  		})
   129  	}
   130  }
   131  
   132  func Test_downloadRun(t *testing.T) {
   133  	tests := []struct {
   134  		name       string
   135  		isTTY      bool
   136  		opts       DownloadOptions
   137  		wantErr    string
   138  		wantStdout string
   139  		wantStderr string
   140  		wantFiles  []string
   141  	}{
   142  		{
   143  			name:  "download all assets",
   144  			isTTY: true,
   145  			opts: DownloadOptions{
   146  				TagName:     "v1.2.3",
   147  				Destination: ".",
   148  				Concurrency: 2,
   149  			},
   150  			wantStdout: ``,
   151  			wantStderr: ``,
   152  			wantFiles: []string{
   153  				"linux.tgz",
   154  				"windows-32bit.zip",
   155  				"windows-64bit.zip",
   156  			},
   157  		},
   158  		{
   159  			name:  "download assets matching pattern into destination directory",
   160  			isTTY: true,
   161  			opts: DownloadOptions{
   162  				TagName:      "v1.2.3",
   163  				FilePatterns: []string{"windows-*.zip"},
   164  				Destination:  "tmp/assets",
   165  				Concurrency:  2,
   166  			},
   167  			wantStdout: ``,
   168  			wantStderr: ``,
   169  			wantFiles: []string{
   170  				"tmp/assets/windows-32bit.zip",
   171  				"tmp/assets/windows-64bit.zip",
   172  			},
   173  		},
   174  		{
   175  			name:  "no match for pattern",
   176  			isTTY: true,
   177  			opts: DownloadOptions{
   178  				TagName:      "v1.2.3",
   179  				FilePatterns: []string{"linux*.zip"},
   180  				Destination:  ".",
   181  				Concurrency:  2,
   182  			},
   183  			wantStdout: ``,
   184  			wantStderr: ``,
   185  			wantErr:    "no assets match the file pattern",
   186  		},
   187  	}
   188  	for _, tt := range tests {
   189  		t.Run(tt.name, func(t *testing.T) {
   190  			tempDir := t.TempDir()
   191  			tt.opts.Destination = filepath.Join(tempDir, tt.opts.Destination)
   192  
   193  			io, _, stdout, stderr := iostreams.Test()
   194  			io.SetStdoutTTY(tt.isTTY)
   195  			io.SetStdinTTY(tt.isTTY)
   196  			io.SetStderrTTY(tt.isTTY)
   197  
   198  			fakeHTTP := &httpmock.Registry{}
   199  			fakeHTTP.Register(httpmock.REST("GET", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StringResponse(`{
   200  				"assets": [
   201  					{ "name": "windows-32bit.zip", "size": 12,
   202  					  "url": "https://api.github.com/assets/1234" },
   203  					{ "name": "windows-64bit.zip", "size": 34,
   204  					  "url": "https://api.github.com/assets/3456" },
   205  					{ "name": "linux.tgz", "size": 56,
   206  					  "url": "https://api.github.com/assets/5678" }
   207  				]
   208  			}`))
   209  			fakeHTTP.Register(httpmock.REST("GET", "assets/1234"), httpmock.StringResponse(`1234`))
   210  			fakeHTTP.Register(httpmock.REST("GET", "assets/3456"), httpmock.StringResponse(`3456`))
   211  			fakeHTTP.Register(httpmock.REST("GET", "assets/5678"), httpmock.StringResponse(`5678`))
   212  
   213  			tt.opts.IO = io
   214  			tt.opts.HttpClient = func() (*http.Client, error) {
   215  				return &http.Client{Transport: fakeHTTP}, nil
   216  			}
   217  			tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
   218  				return ghrepo.FromFullName("OWNER/REPO")
   219  			}
   220  
   221  			err := downloadRun(&tt.opts)
   222  			if tt.wantErr != "" {
   223  				require.EqualError(t, err, tt.wantErr)
   224  				return
   225  			} else {
   226  				require.NoError(t, err)
   227  			}
   228  
   229  			assert.Equal(t, "application/octet-stream", fakeHTTP.Requests[1].Header.Get("Accept"))
   230  
   231  			assert.Equal(t, tt.wantStdout, stdout.String())
   232  			assert.Equal(t, tt.wantStderr, stderr.String())
   233  
   234  			downloadedFiles, err := listFiles(tempDir)
   235  			require.NoError(t, err)
   236  			assert.Equal(t, tt.wantFiles, downloadedFiles)
   237  		})
   238  	}
   239  }
   240  
   241  func listFiles(dir string) ([]string, error) {
   242  	var files []string
   243  	err := filepath.Walk(dir, func(p string, f os.FileInfo, err error) error {
   244  		if !f.IsDir() {
   245  			rp, err := filepath.Rel(dir, p)
   246  			if err != nil {
   247  				return err
   248  			}
   249  			files = append(files, filepath.ToSlash(rp))
   250  		}
   251  		return err
   252  	})
   253  	return files, err
   254  }