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 }