github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/googlephotos/googlephotos_test.go (about)

     1  package googlephotos
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"path"
     9  	"testing"
    10  	"time"
    11  
    12  	_ "github.com/rclone/rclone/backend/local"
    13  	"github.com/rclone/rclone/fs"
    14  	"github.com/rclone/rclone/fs/hash"
    15  	"github.com/rclone/rclone/fstest"
    16  	"github.com/rclone/rclone/lib/random"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  const (
    22  	// We have two different files here as Google Photos will uniq
    23  	// them otherwise which confuses the tests as the filename is
    24  	// unexpected.
    25  	fileNameAlbum  = "rclone-test-image1.jpg"
    26  	fileNameUpload = "rclone-test-image2.jpg"
    27  )
    28  
    29  func TestIntegration(t *testing.T) {
    30  	ctx := context.Background()
    31  	fstest.Initialise()
    32  
    33  	// Create Fs
    34  	if *fstest.RemoteName == "" {
    35  		*fstest.RemoteName = "TestGooglePhotos:"
    36  	}
    37  	f, err := fs.NewFs(ctx, *fstest.RemoteName)
    38  	if err == fs.ErrorNotFoundInConfigFile {
    39  		t.Skipf("Couldn't create google photos backend - skipping tests: %v", err)
    40  	}
    41  	require.NoError(t, err)
    42  
    43  	// Create local Fs pointing at testfiles
    44  	localFs, err := fs.NewFs(ctx, "testfiles")
    45  	require.NoError(t, err)
    46  
    47  	t.Run("CreateAlbum", func(t *testing.T) {
    48  		albumName := "album/rclone-test-" + random.String(24)
    49  		err = f.Mkdir(ctx, albumName)
    50  		require.NoError(t, err)
    51  		remote := albumName + "/" + fileNameAlbum
    52  
    53  		t.Run("PutFile", func(t *testing.T) {
    54  			srcObj, err := localFs.NewObject(ctx, fileNameAlbum)
    55  			require.NoError(t, err)
    56  			in, err := srcObj.Open(ctx)
    57  			require.NoError(t, err)
    58  			dstObj, err := f.Put(ctx, in, fs.NewOverrideRemote(srcObj, remote))
    59  			require.NoError(t, err)
    60  			assert.Equal(t, remote, dstObj.Remote())
    61  			_ = in.Close()
    62  			remoteWithID := addFileID(remote, dstObj.(*Object).id)
    63  
    64  			t.Run("ObjectFs", func(t *testing.T) {
    65  				assert.Equal(t, f, dstObj.Fs())
    66  			})
    67  
    68  			t.Run("ObjectString", func(t *testing.T) {
    69  				assert.Equal(t, remote, dstObj.String())
    70  				assert.Equal(t, "<nil>", (*Object)(nil).String())
    71  			})
    72  
    73  			t.Run("ObjectHash", func(t *testing.T) {
    74  				h, err := dstObj.Hash(ctx, hash.MD5)
    75  				assert.Equal(t, "", h)
    76  				assert.Equal(t, hash.ErrUnsupported, err)
    77  			})
    78  
    79  			t.Run("ObjectSize", func(t *testing.T) {
    80  				assert.Equal(t, int64(-1), dstObj.Size())
    81  				f.(*Fs).opt.ReadSize = true
    82  				defer func() {
    83  					f.(*Fs).opt.ReadSize = false
    84  				}()
    85  				size := dstObj.Size()
    86  				assert.True(t, size > 1000, fmt.Sprintf("Size too small %d", size))
    87  			})
    88  
    89  			t.Run("ObjectSetModTime", func(t *testing.T) {
    90  				err := dstObj.SetModTime(ctx, time.Now())
    91  				assert.Equal(t, fs.ErrorCantSetModTime, err)
    92  			})
    93  
    94  			t.Run("ObjectStorable", func(t *testing.T) {
    95  				assert.True(t, dstObj.Storable())
    96  			})
    97  
    98  			t.Run("ObjectOpen", func(t *testing.T) {
    99  				in, err := dstObj.Open(ctx)
   100  				require.NoError(t, err)
   101  				buf, err := io.ReadAll(in)
   102  				require.NoError(t, err)
   103  				require.NoError(t, in.Close())
   104  				assert.True(t, len(buf) > 1000)
   105  				contentType := http.DetectContentType(buf[:512])
   106  				assert.Equal(t, "image/jpeg", contentType)
   107  			})
   108  
   109  			t.Run("CheckFileInAlbum", func(t *testing.T) {
   110  				entries, err := f.List(ctx, albumName)
   111  				require.NoError(t, err)
   112  				assert.Equal(t, 1, len(entries))
   113  				assert.Equal(t, remote, entries[0].Remote())
   114  				assert.Equal(t, "2013-07-26 08:57:21 +0000 UTC", entries[0].ModTime(ctx).String())
   115  			})
   116  
   117  			// Check it is there in the date/month/year hierarchy
   118  			// 2013-07-13 is the creation date of the folder
   119  			checkPresent := func(t *testing.T, objPath string) {
   120  				entries, err := f.List(ctx, objPath)
   121  				require.NoError(t, err)
   122  				found := false
   123  				for _, entry := range entries {
   124  					leaf := path.Base(entry.Remote())
   125  					if leaf == fileNameAlbum || leaf == remoteWithID {
   126  						found = true
   127  					}
   128  				}
   129  				assert.True(t, found, fmt.Sprintf("didn't find %q in %q", fileNameAlbum, objPath))
   130  			}
   131  
   132  			t.Run("CheckInByYear", func(t *testing.T) {
   133  				checkPresent(t, "media/by-year/2013")
   134  			})
   135  
   136  			t.Run("CheckInByMonth", func(t *testing.T) {
   137  				checkPresent(t, "media/by-month/2013/2013-07")
   138  			})
   139  
   140  			t.Run("CheckInByDay", func(t *testing.T) {
   141  				checkPresent(t, "media/by-day/2013/2013-07-26")
   142  			})
   143  
   144  			t.Run("NewObject", func(t *testing.T) {
   145  				o, err := f.NewObject(ctx, remote)
   146  				require.NoError(t, err)
   147  				require.Equal(t, remote, o.Remote())
   148  			})
   149  
   150  			t.Run("NewObjectWithID", func(t *testing.T) {
   151  				o, err := f.NewObject(ctx, remoteWithID)
   152  				require.NoError(t, err)
   153  				require.Equal(t, remoteWithID, o.Remote())
   154  			})
   155  
   156  			t.Run("NewFsIsFile", func(t *testing.T) {
   157  				fNew, err := fs.NewFs(ctx, *fstest.RemoteName+remote)
   158  				assert.Equal(t, fs.ErrorIsFile, err)
   159  				leaf := path.Base(remote)
   160  				o, err := fNew.NewObject(ctx, leaf)
   161  				require.NoError(t, err)
   162  				require.Equal(t, leaf, o.Remote())
   163  			})
   164  
   165  			t.Run("RemoveFileFromAlbum", func(t *testing.T) {
   166  				err = dstObj.Remove(ctx)
   167  				require.NoError(t, err)
   168  
   169  				time.Sleep(time.Second)
   170  
   171  				// Check album empty
   172  				entries, err := f.List(ctx, albumName)
   173  				require.NoError(t, err)
   174  				assert.Equal(t, 0, len(entries))
   175  			})
   176  		})
   177  
   178  		// remove the album
   179  		err = f.Rmdir(ctx, albumName)
   180  		require.Error(t, err) // FIXME doesn't work yet
   181  	})
   182  
   183  	t.Run("UploadMkdir", func(t *testing.T) {
   184  		assert.NoError(t, f.Mkdir(ctx, "upload/dir"))
   185  		assert.NoError(t, f.Mkdir(ctx, "upload/dir/subdir"))
   186  
   187  		t.Run("List", func(t *testing.T) {
   188  			entries, err := f.List(ctx, "upload")
   189  			require.NoError(t, err)
   190  			assert.Equal(t, 1, len(entries))
   191  			assert.Equal(t, "upload/dir", entries[0].Remote())
   192  
   193  			entries, err = f.List(ctx, "upload/dir")
   194  			require.NoError(t, err)
   195  			assert.Equal(t, 1, len(entries))
   196  			assert.Equal(t, "upload/dir/subdir", entries[0].Remote())
   197  		})
   198  
   199  		t.Run("Rmdir", func(t *testing.T) {
   200  			assert.NoError(t, f.Rmdir(ctx, "upload/dir/subdir"))
   201  			assert.NoError(t, f.Rmdir(ctx, "upload/dir"))
   202  
   203  		})
   204  
   205  		t.Run("ListEmpty", func(t *testing.T) {
   206  			entries, err := f.List(ctx, "upload")
   207  			require.NoError(t, err)
   208  			assert.Equal(t, 0, len(entries))
   209  
   210  			_, err = f.List(ctx, "upload/dir")
   211  			assert.Equal(t, fs.ErrorDirNotFound, err)
   212  		})
   213  	})
   214  
   215  	t.Run("Upload", func(t *testing.T) {
   216  		uploadDir := "upload/dir/subdir"
   217  		remote := path.Join(uploadDir, fileNameUpload)
   218  
   219  		srcObj, err := localFs.NewObject(ctx, fileNameUpload)
   220  		require.NoError(t, err)
   221  		in, err := srcObj.Open(ctx)
   222  		require.NoError(t, err)
   223  		dstObj, err := f.Put(ctx, in, fs.NewOverrideRemote(srcObj, remote))
   224  		require.NoError(t, err)
   225  		assert.Equal(t, remote, dstObj.Remote())
   226  		_ = in.Close()
   227  		remoteWithID := addFileID(remote, dstObj.(*Object).id)
   228  
   229  		t.Run("List", func(t *testing.T) {
   230  			entries, err := f.List(ctx, uploadDir)
   231  			require.NoError(t, err)
   232  			require.Equal(t, 1, len(entries))
   233  			assert.Equal(t, remote, entries[0].Remote())
   234  			assert.Equal(t, "2013-07-26 08:57:21 +0000 UTC", entries[0].ModTime(ctx).String())
   235  		})
   236  
   237  		t.Run("NewObject", func(t *testing.T) {
   238  			o, err := f.NewObject(ctx, remote)
   239  			require.NoError(t, err)
   240  			require.Equal(t, remote, o.Remote())
   241  		})
   242  
   243  		t.Run("NewObjectWithID", func(t *testing.T) {
   244  			o, err := f.NewObject(ctx, remoteWithID)
   245  			require.NoError(t, err)
   246  			require.Equal(t, remoteWithID, o.Remote())
   247  		})
   248  
   249  	})
   250  
   251  	t.Run("Name", func(t *testing.T) {
   252  		assert.Equal(t, (*fstest.RemoteName)[:len(*fstest.RemoteName)-1], f.Name())
   253  	})
   254  
   255  	t.Run("Root", func(t *testing.T) {
   256  		assert.Equal(t, "", f.Root())
   257  	})
   258  
   259  	t.Run("String", func(t *testing.T) {
   260  		assert.Equal(t, `Google Photos path ""`, f.String())
   261  	})
   262  
   263  	t.Run("Features", func(t *testing.T) {
   264  		features := f.Features()
   265  		assert.False(t, features.CaseInsensitive)
   266  		assert.True(t, features.ReadMimeType)
   267  	})
   268  
   269  	t.Run("Precision", func(t *testing.T) {
   270  		assert.Equal(t, fs.ModTimeNotSupported, f.Precision())
   271  	})
   272  
   273  	t.Run("Hashes", func(t *testing.T) {
   274  		assert.Equal(t, hash.Set(hash.None), f.Hashes())
   275  	})
   276  
   277  }
   278  
   279  func TestAddID(t *testing.T) {
   280  	assert.Equal(t, "potato {123}", addID("potato", "123"))
   281  	assert.Equal(t, "{123}", addID("", "123"))
   282  }
   283  
   284  func TestFileAddID(t *testing.T) {
   285  	assert.Equal(t, "potato {123}.txt", addFileID("potato.txt", "123"))
   286  	assert.Equal(t, "potato {123}", addFileID("potato", "123"))
   287  	assert.Equal(t, "{123}", addFileID("", "123"))
   288  }
   289  
   290  func TestFindID(t *testing.T) {
   291  	assert.Equal(t, "", findID("potato"))
   292  	ID := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
   293  	assert.Equal(t, ID, findID("potato {"+ID+"}.txt"))
   294  	ID = ID[1:]
   295  	assert.Equal(t, "", findID("potato {"+ID+"}.txt"))
   296  }