github.com/Files-com/files-sdk-go/v3@v3.1.81/file/client_test.go (about)

     1  package file
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	fs2 "io/fs"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  
    17  	files_sdk "github.com/Files-com/files-sdk-go/v3"
    18  	"github.com/Files-com/files-sdk-go/v3/file/manager"
    19  	"github.com/Files-com/files-sdk-go/v3/file/status"
    20  	"github.com/Files-com/files-sdk-go/v3/folder"
    21  	"github.com/Files-com/files-sdk-go/v3/ignore"
    22  	"github.com/Files-com/files-sdk-go/v3/lib"
    23  	"github.com/Files-com/files-sdk-go/v3/lib/test"
    24  	recorder "github.com/dnaeon/go-vcr/recorder"
    25  	"github.com/samber/lo"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func CreateClient(fixture string) (client *Client, r *recorder.Recorder, err error) {
    31  	client = &Client{}
    32  	client.Config, r, err = test.CreateConfig(fixture)
    33  
    34  	return client, r, err
    35  }
    36  
    37  func deletePath(client *Client, path string) {
    38  	err := client.Delete(files_sdk.FileDeleteParams{Path: path})
    39  	var responseError files_sdk.ResponseError
    40  	ok := errors.As(err, &responseError)
    41  	if ok && responseError.Type == "not-found" {
    42  	} else if ok && responseError.Type == "processing-failure/folder-not-empty" {
    43  		err = client.Delete(files_sdk.FileDeleteParams{Path: path, Recursive: lib.Bool(true)})
    44  		ok = errors.As(err, &responseError)
    45  		if ok && responseError.Type == "not-found" {
    46  			//noop
    47  		} else if ok {
    48  			panic(err)
    49  		}
    50  	} else if ok {
    51  		panic(err)
    52  	}
    53  }
    54  
    55  func ignoreSomeErrors(err error) {
    56  	if err != nil && !files_sdk.IsExist(err) {
    57  		panic(err)
    58  	}
    59  }
    60  
    61  func buildScenario(base string, client *Client) {
    62  	folderClient := folder.Client{Config: client.Config}
    63  
    64  	_, err := folderClient.Create(files_sdk.FolderCreateParams{Path: base})
    65  	ignoreSomeErrors(err)
    66  	_, err = folderClient.Create(files_sdk.FolderCreateParams{Path: lib.UrlJoinNoEscape(base, "nested_1")})
    67  	ignoreSomeErrors(err)
    68  	_, err = folderClient.Create(files_sdk.FolderCreateParams{Path: lib.UrlJoinNoEscape(base, "nested_1", "nested_2")})
    69  	ignoreSomeErrors(err)
    70  	_, err = folderClient.Create(files_sdk.FolderCreateParams{Path: lib.UrlJoinNoEscape(base, "nested_1", "nested_2", "nested_3")})
    71  	ignoreSomeErrors(err)
    72  
    73  	client.Upload()
    74  
    75  	err = client.Upload(
    76  		UploadWithSize(9),
    77  		UploadWithDestinationPath(lib.UrlJoinNoEscape(base, "nested_1", "nested_2", "3.text")),
    78  		UploadWithProvidedMtime(time.Date(2010, 11, 17, 20, 34, 58, 651387237, time.UTC)),
    79  		UploadWithReader(strings.NewReader("testing 3")),
    80  	)
    81  
    82  	ignoreSomeErrors(err)
    83  
    84  	err = client.Upload(
    85  		UploadWithSize(9),
    86  		UploadWithDestinationPath(lib.UrlJoinNoEscape(base, "nested_1", "nested_2", "nested_3", "4.text")),
    87  		UploadWithProvidedMtime(time.Date(2010, 11, 17, 20, 34, 58, 651387237, time.UTC)),
    88  		UploadWithReader(strings.NewReader("testing 3")),
    89  	)
    90  	ignoreSomeErrors(err)
    91  }
    92  
    93  func runDownloadScenario(path string, destination string, client *Client) map[string][]JobFile {
    94  	m := &sync.Mutex{}
    95  	results := make(map[string][]JobFile)
    96  
    97  	reporter := func(r JobFile) {
    98  		m.Lock()
    99  		results[r.File.Path] = append(results[r.File.Path], r)
   100  		m.Unlock()
   101  	}
   102  
   103  	job := client.Downloader(
   104  		DownloaderParams{RemotePath: path, LocalPath: destination, EventsReporter: CreateReporter(reporter)},
   105  	)
   106  
   107  	job.Start()
   108  	job.Wait()
   109  
   110  	return results
   111  }
   112  
   113  func CreateReporter(callback Reporter) EventsReporter {
   114  	return CreateFileEvents(callback, append(status.Excluded, append(status.Included, OnBytesChange(status.Uploading))...)...)
   115  }
   116  
   117  func TestClient_UploadFolder(t *testing.T) {
   118  	client, r, err := CreateClient("TestClient_UploadFolder")
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	defer r.Stop()
   123  
   124  	assert := assert.New(t)
   125  	resultsMapMutex := sync.RWMutex{}
   126  	results := make(map[string][]ReporterCall)
   127  
   128  	job := client.Uploader(
   129  		UploaderParams{
   130  			LocalPath:  "../lib",
   131  			RemotePath: "golib",
   132  			EventsReporter: CreateReporter(func(status JobFile) {
   133  				resultsMapMutex.Lock()
   134  				results[status.RemotePath] = append(results[status.RemotePath], ReporterCall{JobFile: status, err: status.Err})
   135  				resultsMapMutex.Unlock()
   136  			}),
   137  			Manager: manager.Default(),
   138  		},
   139  	)
   140  
   141  	job.Start()
   142  	job.Wait()
   143  	files, err := os.ReadDir("../lib")
   144  	assert.NoError(err)
   145  	gitIgnore, err := ignore.New()
   146  	assert.NoError(err)
   147  	for _, f := range files {
   148  		if f.IsDir() {
   149  			continue
   150  		}
   151  		if gitIgnore.MatchesPath(f.Name()) {
   152  			continue
   153  		}
   154  		remotePath := fmt.Sprintf("golib/lib/%v", f.Name())
   155  		assert.Contains(results, remotePath)
   156  		lastStatuses, ok := results[remotePath]
   157  		if !ok {
   158  			continue
   159  		}
   160  		lastStatus := lastStatuses[len(lastStatuses)-1]
   161  		if lastStatus.Err != nil && strings.Contains(lastStatus.Err.Error(), "Requested interaction not found") {
   162  			assert.Equal(status.Errored, lastStatus.Status)
   163  		} else {
   164  			assert.Equal(status.Complete, lastStatus.Status)
   165  			assert.NoError(lastStatus.Err)
   166  		}
   167  	}
   168  	deletePath(client, "golib")
   169  }
   170  
   171  func TestClient_UploadFolder_Dot(t *testing.T) {
   172  	client, r, err := CreateClient("TestClient_UploadFolder_Dot")
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	defer r.Stop()
   177  
   178  	assert := assert.New(t)
   179  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   180  	if err != nil {
   181  		log.Fatal(err)
   182  	}
   183  	defer os.RemoveAll(tmpDir)
   184  
   185  	resultsMapMutex := sync.RWMutex{}
   186  	results := make(map[string][]int64)
   187  	err = os.MkdirAll(filepath.Join(tmpDir, "dot"), 0755)
   188  	assert.NoError(err)
   189  
   190  	f1, _ := os.Create(filepath.Join(tmpDir, "dot/1.text"))
   191  	f1.Write([]byte("hello 1"))
   192  	f1.Close()
   193  
   194  	f2, _ := os.Create(filepath.Join(tmpDir, "dot/2.text"))
   195  	f2.Write([]byte("hello 2"))
   196  	f2.Close()
   197  
   198  	f3, _ := os.Create(filepath.Join(tmpDir, "dot/3.text"))
   199  	f3.Write([]byte("hello 3"))
   200  	f3.Close()
   201  
   202  	currentPwd, _ := os.Getwd()
   203  	err = os.Chdir(filepath.Join(tmpDir, "dot"))
   204  	defer func() {
   205  		os.Chdir(currentPwd)
   206  		os.RemoveAll(filepath.Join(tmpDir, "/dot"))
   207  	}()
   208  	assert.NoError(err)
   209  
   210  	ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
   211  	defer cancel()
   212  
   213  	job := client.Uploader(
   214  		UploaderParams{
   215  			LocalPath:  "." + string(os.PathSeparator),
   216  			RemotePath: "go-from-dot",
   217  			EventsReporter: CreateReporter(func(s JobFile) {
   218  				resultsMapMutex.Lock()
   219  				require.NoError(t, s.Err)
   220  
   221  				results[s.File.Path] = append(results[s.File.Path], s.TransferBytes)
   222  				resultsMapMutex.Unlock()
   223  			}),
   224  		}, files_sdk.WithContext(ctx))
   225  	job.Start()
   226  	job.Wait()
   227  	assert.Contains(results, "go-from-dot/1.text")
   228  	assert.Contains(results, "go-from-dot/2.text")
   229  	assert.Contains(results, "go-from-dot/3.text")
   230  	assert.Equal(int64(7), job.Statuses[0].TransferBytes())
   231  	assert.Equal(int64(7), job.Statuses[1].TransferBytes())
   232  	assert.Equal(int64(7), job.Statuses[2].TransferBytes())
   233  
   234  	deletePath(client, "go-from-dot")
   235  }
   236  
   237  func TestClient_UploadFolder_Relative(t *testing.T) {
   238  	client, r, err := CreateClient("TestClient_UploadFolder_Relative")
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  	defer r.Stop()
   243  
   244  	assert := assert.New(t)
   245  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   246  	if err != nil {
   247  		log.Fatal(err)
   248  	}
   249  	defer os.RemoveAll(tmpDir)
   250  	resultsMapMutex := sync.RWMutex{}
   251  	results := make(map[string][]int64)
   252  
   253  	err = os.MkdirAll(filepath.Join(tmpDir, "relative"), 0755)
   254  	assert.NoError(err)
   255  
   256  	f1, _ := os.Create(filepath.Join(tmpDir, "relative", "1.text"))
   257  	f1.Write([]byte("hello 1"))
   258  	f1.Close()
   259  
   260  	f2, _ := os.Create(filepath.Join(tmpDir, "relative", "2.text"))
   261  	f2.Write([]byte("hello 2"))
   262  	f2.Close()
   263  
   264  	f3, _ := os.Create(filepath.Join(tmpDir, "relative", "3.text"))
   265  	f3.Write([]byte("hello 3"))
   266  	f3.Close()
   267  
   268  	currentPwd, _ := os.Getwd()
   269  	err = os.Chdir(tmpDir)
   270  	defer os.Chdir(currentPwd)
   271  	assert.NoError(err)
   272  
   273  	job := client.Uploader(
   274  		UploaderParams{
   275  			LocalPath:  "relative" + string(os.PathSeparator),
   276  			RemotePath: "relative",
   277  			EventsReporter: CreateReporter(func(status JobFile) {
   278  				resultsMapMutex.Lock()
   279  				results[status.File.Path] = append(results[status.File.Path], status.TransferBytes)
   280  				resultsMapMutex.Unlock()
   281  			}),
   282  		})
   283  	job.Start()
   284  	job.Wait()
   285  	assert.Contains(results, "relative/1.text")
   286  	assert.Contains(results, "relative/2.text")
   287  	assert.Contains(results, "relative/3.text")
   288  	assert.Equal(int64(7), job.Statuses[0].TransferBytes())
   289  	assert.Equal(int64(7), job.Statuses[1].TransferBytes())
   290  	assert.Equal(int64(7), job.Statuses[2].TransferBytes())
   291  	assert.Equal(int64(21), job.TotalBytes(status.Valid...))
   292  	assert.Equal(true, job.All(status.Ended...))
   293  
   294  	deletePath(client, "relative")
   295  }
   296  
   297  func TestClient_Uploader(t *testing.T) {
   298  	client, r, err := CreateClient("TestClient_Uploader")
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	defer r.Stop()
   303  	assert := assert.New(t)
   304  
   305  	uploadPath := ".." + string(os.PathSeparator) + "LICENSE"
   306  	job := client.Uploader(UploaderParams{LocalPath: uploadPath})
   307  	job.Start()
   308  	job.Wait()
   309  	assert.Equal(true, job.Started.Called())
   310  	assert.Equal(true, job.Scanning.Called())
   311  	assert.Equal(true, job.EndScanning.Called())
   312  	assert.Equal(true, job.Finished.Called())
   313  	assert.Equal(false, job.Canceled.Called())
   314  	assert.Equal("LICENSE", job.Files()[0].DisplayName)
   315  	assert.Equal(1, job.Count())
   316  	assert.Equal(int64(1102), job.TotalBytes())
   317  	assert.Equal(true, job.All(status.Ended...))
   318  
   319  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   320  	if err != nil {
   321  		log.Fatal(err)
   322  	}
   323  	defer os.RemoveAll(tmpDir)
   324  
   325  	tempFile, err := os.CreateTemp(tmpDir, "LICENSE")
   326  	if err != nil {
   327  		panic(err)
   328  	}
   329  	file, err := client.DownloadToFile(files_sdk.FileDownloadParams{Path: "LICENSE"}, tempFile.Name())
   330  	assert.NoError(err)
   331  
   332  	assert.Equal(file.DisplayName, "LICENSE")
   333  
   334  	downloadData, err := os.ReadFile(tempFile.Name())
   335  	if err != nil {
   336  		panic(err)
   337  	}
   338  	localData, err := os.ReadFile(uploadPath)
   339  	if err != nil {
   340  		panic(err)
   341  	}
   342  	assert.Equal(string(downloadData), string(localData))
   343  	defer os.Remove(tempFile.Name())
   344  }
   345  
   346  func TestClient_UploadFile_To_Existing_Dir(t *testing.T) {
   347  	client, r, err := CreateClient("TestClient_UploadFile_To_Existing_Dir")
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  	defer r.Stop()
   352  	assert := assert.New(t)
   353  
   354  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   355  	if err != nil {
   356  		log.Fatal(err)
   357  	}
   358  	defer os.RemoveAll(tmpDir)
   359  
   360  	folderClient := folder.Client{Config: client.Config}
   361  	_, err = folderClient.Create(files_sdk.FolderCreateParams{Path: "docs"})
   362  	defer deletePath(client, "docs")
   363  
   364  	assert.NoError(err)
   365  	uploadPath := ".." + string(os.PathSeparator) + "LICENSE"
   366  	job := client.Uploader(UploaderParams{LocalPath: uploadPath, RemotePath: "docs"})
   367  	job.Start()
   368  	job.Wait()
   369  	tempFile, err := os.CreateTemp(tmpDir, "LICENSE")
   370  	if err != nil {
   371  		panic(err)
   372  	}
   373  	file, err := client.DownloadToFile(files_sdk.FileDownloadParams{Path: "docs/LICENSE"}, tempFile.Name())
   374  	assert.NoError(err)
   375  
   376  	assert.Equal(file.DisplayName, "LICENSE")
   377  
   378  	downloadData, err := os.ReadFile(tempFile.Name())
   379  	if err != nil {
   380  		panic(err)
   381  	}
   382  	localData, err := os.ReadFile(uploadPath)
   383  	if err != nil {
   384  		panic(err)
   385  	}
   386  	assert.Equal(string(downloadData), string(localData))
   387  	defer os.Remove(tempFile.Name())
   388  }
   389  
   390  func TestClient_UploadFile_To_NonExistingPath(t *testing.T) {
   391  	client, r, err := CreateClient("TestClient_UploadFile_To_NonExistingPath")
   392  	if err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	defer r.Stop()
   396  	assert := assert.New(t)
   397  
   398  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   399  	if err != nil {
   400  		log.Fatal(err)
   401  	}
   402  	defer os.RemoveAll(tmpDir)
   403  
   404  	deletePath(client, "taco")
   405  	uploadPath := ".." + string(os.PathSeparator) + "LICENSE"
   406  	job := client.Uploader(UploaderParams{LocalPath: uploadPath, RemotePath: "taco"})
   407  	defer deletePath(client, "taco")
   408  	job.Start()
   409  	job.Wait()
   410  	tempFile, _ := os.CreateTemp(tmpDir, "LICENSE")
   411  	_, err = filepath.Abs(filepath.Dir(tempFile.Name()))
   412  	if err != nil {
   413  		panic(err)
   414  	}
   415  	file, err := client.DownloadToFile(files_sdk.FileDownloadParams{Path: "taco"}, tempFile.Name())
   416  	assert.NoError(err)
   417  
   418  	assert.Equal("taco", file.DisplayName, "because the docs did not exist as a folder it becomes the file")
   419  
   420  	downloadData, err := os.ReadFile(tempFile.Name())
   421  	assert.NoError(err)
   422  	localData, err := os.ReadFile(uploadPath)
   423  	if err != nil {
   424  		panic(err)
   425  	}
   426  	assert.Equal(string(downloadData), string(localData))
   427  	defer os.Remove(tempFile.Name())
   428  }
   429  
   430  func TestClient_UploadFile_To_NonExistingPath_WithSlash(t *testing.T) {
   431  	client, r, err := CreateClient("TestClient_UploadFile_To_NonExistingPath_WithSlash")
   432  	if err != nil {
   433  		t.Fatal(err)
   434  	}
   435  	defer r.Stop()
   436  	assert := assert.New(t)
   437  
   438  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   439  	if err != nil {
   440  		log.Fatal(err)
   441  	}
   442  	defer os.RemoveAll(tmpDir)
   443  
   444  	assert.NoError(err)
   445  	uploadPath := ".." + string(os.PathSeparator) + "LICENSE"
   446  	deletePath(client, "docs")
   447  	job := client.Uploader(UploaderParams{LocalPath: uploadPath, RemotePath: "docs/"})
   448  	defer deletePath(client, "docs")
   449  	job.Start()
   450  	job.Wait()
   451  	tempFile, err := os.CreateTemp(tmpDir, "LICENSE")
   452  	if err != nil {
   453  		panic(err)
   454  	}
   455  	file, err := client.DownloadToFile(files_sdk.FileDownloadParams{Path: "docs/LICENSE"}, tempFile.Name())
   456  	assert.NoError(err)
   457  
   458  	assert.Equal("file", file.Type)
   459  	assert.Equal("LICENSE", file.DisplayName)
   460  
   461  	downloadData, err := os.ReadFile(tempFile.Name())
   462  	if err != nil {
   463  		panic(err)
   464  	}
   465  	localData, err := os.ReadFile(uploadPath)
   466  	if err != nil {
   467  		panic(err)
   468  	}
   469  	assert.Equal(string(downloadData), string(localData))
   470  	defer os.Remove(tempFile.Name())
   471  }
   472  
   473  func TestClient_UploadFolder_as_file2(t *testing.T) {
   474  	client, r, err := CreateClient("TestClient_UploadFolder_as_file2")
   475  	if err != nil {
   476  		t.Fatal(err)
   477  	}
   478  	defer r.Stop()
   479  	assert := assert.New(t)
   480  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   481  	if err != nil {
   482  		log.Fatal(err)
   483  	}
   484  	defer os.RemoveAll(tmpDir)
   485  
   486  	uploadPath := ".." + string(os.PathSeparator) + "LICENSE"
   487  	job := client.Uploader(UploaderParams{LocalPath: uploadPath})
   488  	job.Start()
   489  	job.Wait()
   490  
   491  	assert.Equal(int64(1102), job.TransferBytes())
   492  	assert.Equal(int64(1102), job.TotalBytes())
   493  
   494  	tempFile, err := os.CreateTemp(tmpDir, "LICENSE")
   495  	if err != nil {
   496  		panic(err)
   497  	}
   498  	file, err := client.DownloadToFile(files_sdk.FileDownloadParams{Path: "LICENSE"}, tempFile.Name())
   499  	assert.NoError(err)
   500  
   501  	assert.Equal(file.DisplayName, "LICENSE")
   502  
   503  	downloadData, err := os.ReadFile(tempFile.Name())
   504  	if err != nil {
   505  		panic(err)
   506  	}
   507  	localData, err := os.ReadFile(uploadPath)
   508  	if err != nil {
   509  		panic(err)
   510  	}
   511  	assert.Equal(string(downloadData), string(localData))
   512  	defer os.Remove(tempFile.Name())
   513  }
   514  
   515  func TestClient_UploadFolder_RemotePathWithStartingSlash(t *testing.T) {
   516  	client, r, err := CreateClient("TestClient_UploadFolder_RemotePathWithStartingSlash")
   517  	if err != nil {
   518  		t.Fatal(err)
   519  	}
   520  	defer r.Stop()
   521  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   522  	if err != nil {
   523  		log.Fatal(err)
   524  	}
   525  	defer os.RemoveAll(tmpDir)
   526  
   527  	err = os.MkdirAll(filepath.Join(tmpDir, "test"), 0755)
   528  	assert.NoError(t, err)
   529  
   530  	f1, _ := os.Create(filepath.Join(tmpDir, "test", "1.text"))
   531  	f1.Write([]byte("hello 1"))
   532  	f1.Close()
   533  
   534  	f2, _ := os.Create(filepath.Join(tmpDir, "test", "2.text"))
   535  	f2.Write([]byte("hello 2"))
   536  	f2.Close()
   537  
   538  	f3, _ := os.Create(filepath.Join(tmpDir, "test", "3.text"))
   539  	f3.Write([]byte("hello 3"))
   540  	f3.Close()
   541  	job := client.Uploader(UploaderParams{LocalPath: filepath.Join(tmpDir, "test"), RemotePath: "/test", Manager: manager.Sync()})
   542  	job.Start()
   543  	job.Wait()
   544  	assert.NoError(t, job.Statuses[0].Err())
   545  	assert.Len(t, job.Statuses, 3)
   546  	dir, _ := filepath.Split(job.Statuses[0].RemotePath())
   547  	assert.Equal(t, "test/test/", dir)
   548  }
   549  
   550  func TestClient_UploadFolder_ZeroByteFile(t *testing.T) {
   551  	client, r, err := CreateClient("TestClient_UploadFolder_ZeroByteFile")
   552  	if err != nil {
   553  		t.Fatal(err)
   554  	}
   555  	defer r.Stop()
   556  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   557  	if err != nil {
   558  		log.Fatal(err)
   559  	}
   560  	defer os.RemoveAll(tmpDir)
   561  	err = os.MkdirAll(filepath.Join(tmpDir, "zero_byte_folder"), 0755)
   562  	assert.NoError(t, err)
   563  
   564  	f1, _ := os.Create(filepath.Join(tmpDir, "zero_byte_folder", "zero-byte-file.text"))
   565  	f1.Close()
   566  
   567  	job := client.Uploader(UploaderParams{LocalPath: filepath.Join(tmpDir, "zero_byte_folder"), RemotePath: "", Manager: manager.Sync()})
   568  	job.Start()
   569  	job.Wait()
   570  	require.Len(t, job.Statuses, 1)
   571  	assert.NoError(t, job.Statuses[0].Err())
   572  	assert.Equal(t, "zero_byte_folder/zero-byte-file.text", job.Statuses[0].RemotePath())
   573  
   574  	job = client.Downloader(DownloaderParams{RemotePath: "zero_byte_folder", LocalPath: tmpDir + string(os.PathSeparator)})
   575  	job.Start()
   576  	job.Wait()
   577  	require.Len(t, job.Statuses, 1)
   578  	assert.NoError(t, job.Statuses[0].Err())
   579  }
   580  
   581  func TestClient_DownloadFolder(t *testing.T) {
   582  	client, r, err := CreateClient("TestClient_DownloadFolder")
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  	defer r.Stop()
   587  
   588  	buildScenario("TestClient_DownloadFolder", client)
   589  
   590  	assert := assert.New(t)
   591  
   592  	it, err := client.ListFor(files_sdk.FolderListForParams{
   593  		ListParams: files_sdk.ListParams{PerPage: 1},
   594  		Path:       "TestClient_DownloadFolder/nested_1/nested_2",
   595  	})
   596  
   597  	assert.NoError(err)
   598  	files := files_sdk.FileCollection{}
   599  	for it.Next() {
   600  		files = append(files, it.File())
   601  	}
   602  
   603  	assert.Len(files, 2, "something is wrong with cursor")
   604  
   605  	results := runDownloadScenario("TestClient_DownloadFolder", "download/", client)
   606  	assert.NoError(err)
   607  	assert.Equal(int64(9), results["TestClient_DownloadFolder/nested_1/nested_2/3.text"][2].TransferBytes)
   608  	assert.Equal(int64(9), results["TestClient_DownloadFolder/nested_1/nested_2/nested_3/4.text"][2].TransferBytes)
   609  	os.RemoveAll("download")
   610  }
   611  
   612  func TestClient_DownloadFolder_Smart(t *testing.T) {
   613  	client, r, err := CreateClient("TestClient_DownloadFolder_Smart")
   614  	if err != nil {
   615  		t.Fatal(err)
   616  	}
   617  	defer r.Stop()
   618  	defer os.RemoveAll("download")
   619  
   620  	buildScenario("TestClient_DownloadFolder_Smart", client)
   621  
   622  	results := runDownloadScenario(lib.UrlJoinNoEscape("TestClient_DownloadFolder_Smart", "nested_1", "nested_2", "3.text"), "download"+string(os.PathSeparator), client)
   623  	for _, result := range results {
   624  		for _, f := range result {
   625  			require.NoError(t, f.Err)
   626  		}
   627  	}
   628  
   629  	assert.Len(t, results["TestClient_DownloadFolder_Smart/nested_1/nested_2/3.text"], 3)
   630  	assert.Equal(t, int64(9), results["TestClient_DownloadFolder_Smart/nested_1/nested_2/3.text"][2].TransferBytes)
   631  
   632  	results2 := runDownloadScenario(lib.UrlJoinNoEscape("TestClient_DownloadFolder_Smart", "nested_1", "nested_2")+"/", "download", client)
   633  
   634  	assert.NoError(t, err)
   635  
   636  	path, err := os.Getwd()
   637  	assert.NoError(t, err)
   638  
   639  	require.Len(t, results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/3.text"], 3)
   640  	assert.Equal(t, int64(9), results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/3.text"][2].TransferBytes)
   641  	assert.Equal(t, filepath.Join(path, "download", "3.text"), results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/3.text"][2].LocalPath)
   642  	fileInfo, err := os.Stat(filepath.Join(path, "download", "3.text"))
   643  	require.NoError(t, err)
   644  	assert.Equal(t, int64(9), fileInfo.Size())
   645  	require.Len(t, results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/nested_3/4.text"], 3)
   646  	assert.Equal(t, int64(9), results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/nested_3/4.text"][2].TransferBytes)
   647  	assert.Equal(t, filepath.Join(path, "download", "nested_3", "4.text"), results2["TestClient_DownloadFolder_Smart/nested_1/nested_2/nested_3/4.text"][2].LocalPath)
   648  }
   649  
   650  func TestClient_DownloadFolder_file_to_file(t *testing.T) {
   651  	client, r, err := CreateClient("TestClient_DownloadFolder_file_to_file")
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  	defer r.Stop()
   656  
   657  	buildScenario("TestClient_DownloadFolder_file_to_file", client)
   658  	assert := assert.New(t)
   659  
   660  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   661  	if err != nil {
   662  		log.Fatal(err)
   663  	}
   664  	defer os.RemoveAll(tmpDir)
   665  
   666  	results := runDownloadScenario(lib.UrlJoinNoEscape("TestClient_DownloadFolder_file_to_file", "nested_1", "nested_2", "3.text"), filepath.Join(tmpDir, "3.text"), client)
   667  	assert.NoError(err)
   668  	for _, result := range results {
   669  		for _, f := range result {
   670  			require.NoError(t, f.Err)
   671  		}
   672  	}
   673  	assert.Equal(int64(9), results["TestClient_DownloadFolder_file_to_file/nested_1/nested_2/3.text"][2].TransferBytes)
   674  }
   675  
   676  func TestClient_DownloadFolder_file_to_implicit(t *testing.T) {
   677  	client, r, err := CreateClient("TestClient_DownloadFolder_file_to_implicit")
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	defer r.Stop()
   682  
   683  	buildScenario("file_to_implicit", client)
   684  	assert := assert.New(t)
   685  	results := runDownloadScenario(lib.UrlJoinNoEscape("file_to_implicit", "nested_1", "nested_2", "3.text"), "", client)
   686  	assert.NoError(err)
   687  	for _, result := range results {
   688  		for _, f := range result {
   689  			require.NoError(t, f.Err)
   690  		}
   691  	}
   692  	assert.Equal(int64(9), results["file_to_implicit/nested_1/nested_2/3.text"][2].TransferBytes)
   693  	os.RemoveAll("3.text")
   694  }
   695  
   696  func TestClient_DownloadFolder_file_only(t *testing.T) {
   697  	client, r, err := CreateClient("TestClient_DownloadFolder_file_only")
   698  	if err != nil {
   699  		t.Fatal(err)
   700  	}
   701  	defer r.Stop()
   702  
   703  	err = client.Upload(
   704  		UploadWithSize(5),
   705  		UploadWithDestinationPath("i am at the root.text"),
   706  		UploadWithProvidedMtime(time.Date(2010, 11, 17, 20, 34, 58, 651387237, time.UTC)),
   707  		UploadWithReader(strings.NewReader("hello")),
   708  	)
   709  
   710  	require.NoError(t, err)
   711  
   712  	assert := assert.New(t)
   713  	results := runDownloadScenario("i am at the root.text", "", client)
   714  	assert.NoError(err)
   715  	for _, result := range results {
   716  		for _, f := range result {
   717  			require.NoError(t, f.Err)
   718  		}
   719  	}
   720  	require.Len(t, results["i am at the root.text"], 3)
   721  	assert.Equal(int64(5), results["i am at the root.text"][2].TransferBytes)
   722  	os.RemoveAll("i am at the root.text")
   723  }
   724  
   725  func TestClient_Downloader_Delete_Source(t *testing.T) {
   726  	client, r, err := CreateClient("TestClient_Downloader_Delete_Source")
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  	defer r.Stop()
   731  	assert := assert.New(t)
   732  
   733  	folderClient := folder.Client{Config: client.Config}
   734  
   735  	folderClient.Create(files_sdk.FolderCreateParams{Path: "test-delete-source"})
   736  
   737  	err = client.Upload(
   738  		UploadWithSize(9),
   739  		UploadWithDestinationPath(lib.UrlJoinNoEscape("test-delete-source", "test.text")),
   740  		UploadWithProvidedMtime(time.Date(2010, 11, 17, 20, 34, 58, 651387237, time.UTC)),
   741  		UploadWithReader(strings.NewReader("testing 3")),
   742  	)
   743  
   744  	require.NoError(t, err)
   745  	localPath, err := os.MkdirTemp("", "TestClient_Downloader_Delete_Source")
   746  	require.NoError(t, err)
   747  
   748  	job := client.Downloader(
   749  		DownloaderParams{RemotePath: "test-delete-source", LocalPath: localPath},
   750  	)
   751  	var fi JobFile
   752  	var log status.Log
   753  	job.RegisterFileEvent(func(f JobFile) {
   754  		fi = f
   755  		log, err = DeleteSource{Config: client.Config, Direction: job.Direction}.Call(f)
   756  	}, status.Complete)
   757  	job.Start()
   758  	<-job.Finished.C
   759  	assert.NoError(err)
   760  	assert.Equal("delete source", log.Action)
   761  	assert.Equal(fi.RemotePath, log.Path)
   762  
   763  	_, err = client.Find(files_sdk.FileFindParams{Path: lib.UrlJoinNoEscape("test-delete-source", "test.text")})
   764  	require.NotNil(t, err)
   765  	assert.Equal("Not Found - `Not Found`", err.Error())
   766  	os.RemoveAll("test.text")
   767  }
   768  
   769  func TestClient_Downloader_Move_Source(t *testing.T) {
   770  	client, r, err := CreateClient("TestClient_Downloader_Move_Source")
   771  	if err != nil {
   772  		t.Fatal(err)
   773  	}
   774  	defer r.Stop()
   775  	assert := assert.New(t)
   776  
   777  	folderClient := folder.Client{Config: client.Config}
   778  
   779  	folderClient.Create(files_sdk.FolderCreateParams{Path: "test-move-source"})
   780  
   781  	err = client.Upload(
   782  		UploadWithSize(9),
   783  		UploadWithDestinationPath(lib.UrlJoinNoEscape("test-move-source", "test.text")),
   784  		UploadWithProvidedMtime(time.Date(2010, 11, 17, 20, 34, 58, 651387237, time.UTC)),
   785  		UploadWithReader(strings.NewReader("testing 3")),
   786  	)
   787  	require.NoError(t, err)
   788  	localPath, err := os.MkdirTemp("", "TestClient_Downloader_Move_Source")
   789  	require.NoError(t, err)
   790  	job := client.Downloader(
   791  		DownloaderParams{RemotePath: "test-move-source", LocalPath: localPath},
   792  	)
   793  	var log status.Log
   794  	job.RegisterFileEvent(func(f JobFile) {
   795  		log, err = MoveSource{Config: client.Config, Direction: job.Direction, Path: "test-moved-source"}.Call(f)
   796  	}, status.Complete)
   797  	job.Start()
   798  	job.Wait()
   799  
   800  	require.NoError(t, err)
   801  	assert.Equal("move source", log.Action)
   802  	assert.Equal(filepath.Join("test-moved-source", "test.text"), log.Path)
   803  
   804  	_, err = client.Find(files_sdk.FileFindParams{Path: lib.UrlJoinNoEscape("test-move-source", "test.text")})
   805  	assert.Equal("Not Found - `Not Found`", err.Error())
   806  	_, err = client.Find(files_sdk.FileFindParams{Path: lib.UrlJoinNoEscape("test-moved-source", "test.text")})
   807  	assert.NoError(err)
   808  	os.RemoveAll("test.text")
   809  }
   810  
   811  func TestClient_UploadFolder_Move_Source(t *testing.T) {
   812  	client, r, err := CreateClient("TestClient_UploadFolder_Move_Source")
   813  	if err != nil {
   814  		t.Fatal(err)
   815  	}
   816  	defer r.Stop()
   817  	assert := assert.New(t)
   818  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   819  	if err != nil {
   820  		log.Fatal(err)
   821  	}
   822  	defer os.RemoveAll(tmpDir)
   823  	var log status.Log
   824  
   825  	defer os.RemoveAll(tmpDir)
   826  	err = os.MkdirAll(filepath.Join(tmpDir, "move-source"), 0755)
   827  	assert.NoError(err)
   828  
   829  	tempFile, err := os.Create(filepath.Join(tmpDir, "move-source", "upload-move-source.text"))
   830  	assert.NoError(err)
   831  	tempFile.Write([]byte("testing"))
   832  	require.NoError(t, tempFile.Close())
   833  	job := client.Uploader(UploaderParams{LocalPath: tempFile.Name()})
   834  	job.RegisterFileEvent(func(f JobFile) {
   835  		fmt.Println("RegisterFileEvent")
   836  		log, err = MoveSource{Config: client.Config, Direction: job.Direction, Path: filepath.Join(tmpDir, "move-source", "test-moved-source.text")}.Call(f)
   837  	}, status.Complete)
   838  	job.Start()
   839  	job.Wait()
   840  	assert.Equal(false, job.Any(status.Errored))
   841  	assert.NoError(err)
   842  	assert.Equal("move source", log.Action)
   843  	assert.Equal(filepath.Join(tmpDir, "move-source", "test-moved-source.text"), log.Path)
   844  	stat, err := os.Stat(log.Path)
   845  	require.NoError(t, err)
   846  	assert.Equal("test-moved-source.text", stat.Name())
   847  	tempFile.Close()
   848  }
   849  
   850  func TestClient_UploadFolder_Move_Source_Missing_Dir(t *testing.T) {
   851  	client, r, err := CreateClient("TestClient_UploadFolder_Move_Source_Missing_Dir")
   852  	if err != nil {
   853  		t.Fatal(err)
   854  	}
   855  	defer r.Stop()
   856  	assert := assert.New(t)
   857  
   858  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   859  	if err != nil {
   860  		log.Fatal(err)
   861  	}
   862  	defer os.RemoveAll(tmpDir)
   863  
   864  	var log status.Log
   865  	err = os.MkdirAll(filepath.Join(tmpDir, "move-source-dir"), 0755)
   866  	assert.NoError(err)
   867  	tempFile, err := os.Create(filepath.Join(tmpDir, "move-source-dir", "upload-move-source.text"))
   868  	assert.NoError(err)
   869  	tempFile.Write([]byte("testing"))
   870  	tempFile.Close()
   871  	job := client.Uploader(UploaderParams{LocalPath: filepath.Join(tmpDir, "move-source-dir") + string(os.PathSeparator)})
   872  	job.RegisterFileEvent(func(f JobFile) {
   873  		log, err = MoveSource{Config: client.Config, Direction: job.Direction, Path: filepath.Join(tmpDir, "moved-source-dir")}.Call(f)
   874  	}, status.Complete)
   875  	job.Start()
   876  	job.Wait()
   877  	erroredFile, ok := job.Find(status.Errored)
   878  	if ok {
   879  		assert.NoError(erroredFile.Err(), erroredFile.LocalPath())
   880  	}
   881  	require.Equal(t, false, job.Any(status.Errored), "")
   882  	assert.NoError(err)
   883  	assert.Equal("move source", log.Action)
   884  	assert.Equal(filepath.Join(tmpDir, "moved-source-dir", "upload-move-source.text"), log.Path)
   885  	stat, err := os.Stat(log.Path)
   886  	assert.NoError(err)
   887  	assert.Equal("upload-move-source.text", stat.Name())
   888  	assert.Equal(false, stat.IsDir())
   889  
   890  	_, err = os.Stat(filepath.Join(tmpDir, "move-source-dir", "upload-move-source.text"))
   891  	assert.Equal(true, os.IsNotExist(err))
   892  }
   893  
   894  func TestClient_Downloader_Move_Source_Missing_Dir(t *testing.T) {
   895  	client, r, err := CreateClient("TestClient_Downloader_Move_Source_Missing_Dir")
   896  	if err != nil {
   897  		t.Fatal(err)
   898  	}
   899  	defer r.Stop()
   900  	assert := assert.New(t)
   901  
   902  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   903  	if err != nil {
   904  		log.Fatal(err)
   905  	}
   906  	defer os.RemoveAll(tmpDir)
   907  
   908  	buildScenario("TestClient_Downloader_Move_Source_Missing_Dir", client)
   909  	os.MkdirAll(filepath.Join(tmpDir, "TestClient_Downloader_Move_Source_Missing_Dir"), 0755)
   910  
   911  	logChan := make(chan status.Log)
   912  	errChan := make(chan error)
   913  	job := client.Downloader(
   914  		DownloaderParams{
   915  			RemotePath: "TestClient_Downloader_Move_Source_Missing_Dir",
   916  			LocalPath:  filepath.Join(tmpDir, "TestClient_Downloader_Move_Source_Missing_Dir") + string(os.PathSeparator),
   917  		},
   918  	)
   919  	job.RegisterFileEvent(func(f JobFile) {
   920  		moveLog, err := MoveSource{Config: client.Config, Direction: job.Direction, Path: "TestClient_Downloader_Move_Source_Missing_Dir-moved"}.Call(f)
   921  		logChan <- moveLog
   922  		errChan <- err
   923  	}, status.Complete)
   924  	job.Start()
   925  
   926  	fileValues := []string{
   927  		"TestClient_Downloader_Move_Source_Missing_Dir-moved/nested_1/nested_2/3.text",
   928  		"TestClient_Downloader_Move_Source_Missing_Dir-moved/nested_1/nested_2/nested_3/4.text",
   929  	}
   930  	files := make(map[string]string)
   931  	files[fileValues[0]] = fileValues[0]
   932  	files[fileValues[1]] = fileValues[1]
   933  
   934  	log1 := <-logChan
   935  	assert.Equal("move source", log1.Action)
   936  	assert.Equal(files[lib.Path{Path: log1.Path}.NormalizePathSystemForAPI().String()], lib.Path{Path: log1.Path}.NormalizePathSystemForAPI().String())
   937  	assert.NoError(<-errChan)
   938  
   939  	log2 := <-logChan
   940  	assert.Equal("move source", log2.Action)
   941  	assert.Equal(files[lib.Path{Path: log2.Path}.NormalizePathSystemForAPI().String()], lib.Path{Path: log2.Path}.NormalizePathSystemForAPI().String())
   942  	assert.NoError(<-errChan)
   943  
   944  	job.Wait()
   945  
   946  	assert.Equal(false, job.Any(status.Errored))
   947  
   948  	movedDir, err := client.Find(files_sdk.FileFindParams{Path: "TestClient_Downloader_Move_Source_Missing_Dir-moved"})
   949  	assert.NoError(err)
   950  	assert.Equal("TestClient_Downloader_Move_Source_Missing_Dir-moved", movedDir.Path)
   951  	assert.Equal("directory", movedDir.Type)
   952  }
   953  
   954  func TestClient_UploadFile_Delete_Source(t *testing.T) {
   955  	client, r, err := CreateClient("TestClient_UploadFile_Delete_Source")
   956  	if err != nil {
   957  		t.Fatal(err)
   958  	}
   959  	defer r.Stop()
   960  	assert := assert.New(t)
   961  	tmpDir, err := os.MkdirTemp(os.TempDir(), "client_test")
   962  	if err != nil {
   963  		log.Fatal(err)
   964  	}
   965  	defer os.RemoveAll(tmpDir)
   966  
   967  	var log status.Log
   968  	tempFile, err := os.Create(filepath.Join(tmpDir, "upload-delete-source.text"))
   969  	assert.NoError(err)
   970  	tempFile.Write([]byte("testing"))
   971  	require.NoError(t, tempFile.Close())
   972  	var fi JobFile
   973  	job := client.Uploader(UploaderParams{LocalPath: tempFile.Name()})
   974  	job.RegisterFileEvent(func(f JobFile) {
   975  		fi = f
   976  		log, err = DeleteSource{Config: client.Config, Direction: job.Direction}.Call(f)
   977  	}, status.Complete)
   978  	job.Start()
   979  	job.Wait()
   980  	assert.Equal(false, job.Any(status.Errored))
   981  	assert.NoError(err)
   982  	assert.Equal("delete source", log.Action)
   983  	assert.Equal(fi.LocalPath, log.Path)
   984  	tempFile.Close()
   985  	os.Remove(tempFile.Name())
   986  }
   987  
   988  func TestClient_Uploader_Files(t *testing.T) {
   989  	client, r, err := CreateClient("TestClient_Uploader_Files")
   990  	if err != nil {
   991  		t.Fatal(err)
   992  	}
   993  	defer r.Stop()
   994  	assert := assert.New(t)
   995  	tmpDir := t.TempDir()
   996  
   997  	filesAndStatus := []struct {
   998  		name   string
   999  		status string
  1000  		size   int
  1001  	}{{name: "1 (1).text", status: "complete", size: 24}, {name: "2.text", status: "complete", size: 24}, {name: "3.pdf", status: "ignored"}}
  1002  	var filePaths []string
  1003  	for _, file := range filesAndStatus {
  1004  		f, err := os.Create(filepath.Join(tmpDir, file.name))
  1005  		assert.NoError(err)
  1006  		f.Write([]byte("hello how are you doing?"))
  1007  		f.Close()
  1008  		if file.status == "complete" {
  1009  			filePaths = append(filePaths, f.Name())
  1010  		}
  1011  	}
  1012  
  1013  	job := client.Uploader(UploaderParams{LocalPath: tmpDir + string(os.PathSeparator), LocalPaths: filePaths})
  1014  	job.Start()
  1015  	job.Wait()
  1016  
  1017  	assert.Len(job.Statuses, 2)
  1018  	assert.Equal(filePaths[0], job.Statuses[0].LocalPath())
  1019  	assert.Equal(status.Complete, job.Statuses[0].Status())
  1020  	assert.NoError(job.Statuses[0].Err())
  1021  
  1022  	assert.Equal(filePaths[1], job.Statuses[1].LocalPath())
  1023  	assert.Equal(status.Complete, job.Statuses[1].Status())
  1024  	assert.NoError(job.Statuses[1].Err())
  1025  }
  1026  
  1027  func TestClient_Uploader_Directories(t *testing.T) {
  1028  	client, r, err := CreateClient("TestClient_Uploader_Directories")
  1029  	if err != nil {
  1030  		t.Fatal(err)
  1031  	}
  1032  	defer r.Stop()
  1033  	assert := assert.New(t)
  1034  	tmpDir := t.TempDir()
  1035  
  1036  	filesAndStatus := []struct {
  1037  		name   string
  1038  		status string
  1039  		size   int
  1040  	}{{name: "A/1.text", status: "complete", size: 24}, {name: "B/2.text", status: "complete", size: 24}, {name: "B/Z/4.text", status: "complete", size: 24}, {name: "3.text", status: "complete", size: 24}}
  1041  	for index, file := range filesAndStatus {
  1042  		file.name = filepath.Join(tmpDir, file.name)
  1043  		require.NoError(t, os.MkdirAll(filepath.Dir(file.name), 0750))
  1044  		filesAndStatus[index] = file
  1045  		f, err := os.Create(file.name)
  1046  		assert.NoError(err)
  1047  		f.Write([]byte("hello how are you doing?"))
  1048  		f.Close()
  1049  	}
  1050  
  1051  	job := client.Uploader(
  1052  		UploaderParams{
  1053  			LocalPath: tmpDir + string(os.PathSeparator),
  1054  			LocalPaths: []string{
  1055  				filepath.Join(tmpDir, "A") + string(os.PathSeparator),
  1056  				filepath.Join(tmpDir, "B") + string(os.PathSeparator),
  1057  				filepath.Join(tmpDir, "3.text"),
  1058  			},
  1059  		},
  1060  	)
  1061  	job.Start()
  1062  	job.Wait()
  1063  
  1064  	require.Equal(t, 4, len(job.Statuses), "the right number of files did not upload")
  1065  	assert.Equal(filesAndStatus[0].name, job.Statuses[0].LocalPath())
  1066  	assert.Equal("1.text", job.Statuses[0].RemotePath())
  1067  	assert.Equal(status.Complete, job.Statuses[0].Status())
  1068  	assert.NoError(job.Statuses[0].Err())
  1069  
  1070  	assert.Equal(filesAndStatus[1].name, job.Statuses[1].LocalPath())
  1071  	assert.Equal("2.text", job.Statuses[1].RemotePath())
  1072  	assert.Equal(status.Complete, job.Statuses[1].Status())
  1073  	assert.NoError(job.Statuses[1].Err())
  1074  
  1075  	assert.Equal(filesAndStatus[2].name, job.Statuses[2].LocalPath())
  1076  	assert.Equal("Z/4.text", job.Statuses[2].RemotePath())
  1077  	assert.Equal(status.Complete, job.Statuses[2].Status())
  1078  	assert.NoError(job.Statuses[2].Err())
  1079  
  1080  	assert.Equal(filesAndStatus[3].name, job.Statuses[3].LocalPath())
  1081  	assert.Equal("3.text", job.Statuses[3].RemotePath())
  1082  	assert.Equal(status.Complete, job.Statuses[3].Status())
  1083  	assert.NoError(job.Statuses[3].Err())
  1084  }
  1085  
  1086  func TestClient_ListForRecursive(t *testing.T) {
  1087  	client, r, err := CreateClient("TestClient_ListForRecursive")
  1088  	if err != nil {
  1089  		t.Fatal(err)
  1090  	}
  1091  	defer r.Stop()
  1092  	assert := assert.New(t)
  1093  	buildScenario("TestClient_ListForRecursive", client)
  1094  
  1095  	it, _ := client.ListForRecursive(files_sdk.FolderListForParams{Path: "/TestClient_ListForRecursive"})
  1096  	var files []RecursiveItem
  1097  	for it.Next() {
  1098  		files = append(files, it.Resource())
  1099  	}
  1100  
  1101  	paths := lo.Map[RecursiveItem, string](files, func(item RecursiveItem, index int) string {
  1102  		return item.Path
  1103  	})
  1104  	assert.Contains(paths, "TestClient_ListForRecursive")
  1105  	assert.Contains(paths, "TestClient_ListForRecursive/nested_1")
  1106  	assert.Contains(paths, "TestClient_ListForRecursive/nested_1/nested_2")
  1107  	assert.Contains(paths, "TestClient_ListForRecursive/nested_1/nested_2/nested_3")
  1108  	assert.Contains(paths, "TestClient_ListForRecursive/nested_1/nested_2/nested_3/4.text")
  1109  	assert.Contains(paths, "TestClient_ListForRecursive/nested_1/nested_2/3.text")
  1110  }
  1111  
  1112  func TestClient_ListForRecursiveInsensitive(t *testing.T) {
  1113  	client, r, err := CreateClient("TestClient_ListForRecursiveInsensitive")
  1114  	if err != nil {
  1115  		t.Fatal(err)
  1116  	}
  1117  	defer r.Stop()
  1118  	assert := assert.New(t)
  1119  	buildScenario("TestClient_ListForRecursiveInsensitive", client)
  1120  
  1121  	it, _ := client.ListForRecursive(files_sdk.FolderListForParams{Path: "/TestcLient_listforrecursiveinseNsitive"})
  1122  	var files []RecursiveItem
  1123  	for it.Next() {
  1124  		files = append(files, it.Resource())
  1125  	}
  1126  
  1127  	require.Equal(t, 6, len(files))
  1128  	paths := lo.Map[RecursiveItem, string](files, func(item RecursiveItem, index int) string {
  1129  		return item.Path
  1130  	})
  1131  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive")
  1132  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive/nested_1")
  1133  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive/nested_1/nested_2")
  1134  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive/nested_1/nested_2/nested_3")
  1135  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive/nested_1/nested_2/nested_3/4.text")
  1136  	assert.Contains(paths, "TestClient_ListForRecursiveInsensitive/nested_1/nested_2/3.text")
  1137  }
  1138  
  1139  func TestClient_ListForRecursive_Error(t *testing.T) {
  1140  	client, r, err := CreateClient("TestClient_ListForRecursive_Error")
  1141  	if err != nil {
  1142  		t.Fatal(err)
  1143  	}
  1144  	defer r.Stop()
  1145  	assert := assert.New(t)
  1146  	it, err := client.ListForRecursive(files_sdk.FolderListForParams{Path: "TestClient_ListForRecursive-Not-Found"})
  1147  	var files []interface{}
  1148  	if err == nil {
  1149  		for it.Next() {
  1150  			files = append(files, it.Current())
  1151  		}
  1152  	}
  1153  
  1154  	assert.Equal(len(files), 0)
  1155  	assert.Equal("open TestClient_ListForRecursive-Not-Found: Authentication Required - `Unauthorized. The API key or Session token is either missing or invalid.`", err.Error())
  1156  }
  1157  
  1158  func TestClient_ListForRecursive_Root(t *testing.T) {
  1159  	client, r, err := CreateClient("TestClient_ListForRecursive_Root")
  1160  	if err != nil {
  1161  		t.Fatal(err)
  1162  	}
  1163  	defer r.Stop()
  1164  	assert := assert.New(t)
  1165  	ctx, cancel := context.WithCancel(context.Background())
  1166  	defer cancel()
  1167  	it, _ := client.ListForRecursive(files_sdk.FolderListForParams{Path: ""}, files_sdk.WithContext(ctx))
  1168  	recursiveItems := make([]RecursiveItem, 0)
  1169  	for it.Next() {
  1170  		if it.Err() != nil {
  1171  			assert.NoError(it.Err())
  1172  			continue
  1173  		}
  1174  
  1175  		recursiveItems = append(recursiveItems, it.Resource())
  1176  		assert.NotEqual(it.Resource().Path, "")
  1177  	}
  1178  	paths := lo.Map[RecursiveItem, string](recursiveItems, func(item RecursiveItem, index int) string {
  1179  		return item.Path
  1180  	})
  1181  	assert.Len(paths, 4)
  1182  	errs := lo.Map[RecursiveItem, error](recursiveItems, func(item RecursiveItem, index int) error {
  1183  		return item.Err()
  1184  	})
  1185  	errs = lo.Reject[error](errs, func(err error, index int) bool {
  1186  		return err == nil
  1187  	})
  1188  	assert.ElementsMatch([]string{"azure", "aws-sftp"}, []string{errs[0].(*fs2.PathError).Path, errs[1].(*fs2.PathError).Path})
  1189  }
  1190  
  1191  func TestClient_UploadFile(t *testing.T) {
  1192  	client, r, err := CreateClient("TestClient_UploadFile")
  1193  	if err != nil {
  1194  		t.Fatal(err)
  1195  	}
  1196  	fileName := filepath.Join(t.TempDir(), "anything")
  1197  	file, err := os.Create(fileName)
  1198  	require.NoError(t, err)
  1199  	file.Write([]byte("anything"))
  1200  	file.Close()
  1201  
  1202  	err = client.UploadFile(fileName, "test/anything")
  1203  	require.NoError(t, err)
  1204  
  1205  	sdkFile, err := client.Find(files_sdk.FileFindParams{Path: "test/anything"})
  1206  	require.NoError(t, err)
  1207  	require.Equal(t, sdkFile.DisplayName, "anything")
  1208  	fs := (&FS{}).Init(client.Config, false).WithContext(context.Background()).(fs2.FS)
  1209  	fsFile, err := fs.Open("test/anything")
  1210  	require.NoError(t, err)
  1211  	fileBytes, err := io.ReadAll(fsFile)
  1212  	require.NoError(t, err)
  1213  	require.Equal(t, "anything", string(fileBytes))
  1214  	r.Stop()
  1215  }
  1216  
  1217  func TestClient_ListFor(t *testing.T) {
  1218  	client, r, err := CreateClient("TestClient_ListFor")
  1219  	if err != nil {
  1220  		t.Fatal(err)
  1221  	}
  1222  
  1223  	buildScenario("TestClient_DownloadFolder", client)
  1224  
  1225  	assert := assert.New(t)
  1226  
  1227  	it, err := client.ListFor(files_sdk.FolderListForParams{
  1228  		ListParams: files_sdk.ListParams{PerPage: 1},
  1229  		Path:       "TestClient_DownloadFolder/nested_1/nested_2",
  1230  	})
  1231  
  1232  	assert.NoError(err)
  1233  	var files []files_sdk.File
  1234  	for it.Next() {
  1235  		if it.File().Type == "directory" {
  1236  			subIt, _ := it.Iterate(it.File().Identifier())
  1237  			for subIt.Next() {
  1238  				subFile := subIt.Current().(files_sdk.File)
  1239  				files = append(files, subFile)
  1240  				loadedFile, err := it.LoadResource(subFile.Identifier())
  1241  				assert.NoError(err)
  1242  				assert.Equal(subFile, loadedFile, "LoadResource with Identifier matches file from list")
  1243  			}
  1244  		}
  1245  		files = append(files, it.File())
  1246  
  1247  	}
  1248  	paths := lo.Map[files_sdk.File, string](files, func(item files_sdk.File, index int) string {
  1249  		return item.Path
  1250  	})
  1251  	assert.Equal([]string{
  1252  		"TestClient_DownloadFolder/nested_1/nested_2/nested_3/4.text",
  1253  		"TestClient_DownloadFolder/nested_1/nested_2/nested_3",
  1254  		"TestClient_DownloadFolder/nested_1/nested_2/3.text",
  1255  	}, paths)
  1256  
  1257  	r.Stop()
  1258  }