github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/backend/drive/drive_internal_test.go (about) 1 package drive 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "io" 8 "io/ioutil" 9 "mime" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/pkg/errors" 15 _ "github.com/rclone/rclone/backend/local" 16 "github.com/rclone/rclone/fs" 17 "github.com/rclone/rclone/fs/hash" 18 "github.com/rclone/rclone/fs/operations" 19 "github.com/rclone/rclone/fstest/fstests" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 "google.golang.org/api/drive/v3" 23 ) 24 25 func TestDriveScopes(t *testing.T) { 26 for _, test := range []struct { 27 in string 28 want []string 29 wantFlag bool 30 }{ 31 {"", []string{ 32 "https://www.googleapis.com/auth/drive", 33 }, false}, 34 {" drive.file , drive.readonly", []string{ 35 "https://www.googleapis.com/auth/drive.file", 36 "https://www.googleapis.com/auth/drive.readonly", 37 }, false}, 38 {" drive.file , drive.appfolder", []string{ 39 "https://www.googleapis.com/auth/drive.file", 40 "https://www.googleapis.com/auth/drive.appfolder", 41 }, true}, 42 } { 43 got := driveScopes(test.in) 44 assert.Equal(t, test.want, got, test.in) 45 gotFlag := driveScopesContainsAppFolder(got) 46 assert.Equal(t, test.wantFlag, gotFlag, test.in) 47 } 48 } 49 50 /* 51 var additionalMimeTypes = map[string]string{ 52 "application/vnd.ms-excel.sheet.macroenabled.12": ".xlsm", 53 "application/vnd.ms-excel.template.macroenabled.12": ".xltm", 54 "application/vnd.ms-powerpoint.presentation.macroenabled.12": ".pptm", 55 "application/vnd.ms-powerpoint.slideshow.macroenabled.12": ".ppsm", 56 "application/vnd.ms-powerpoint.template.macroenabled.12": ".potm", 57 "application/vnd.ms-powerpoint": ".ppt", 58 "application/vnd.ms-word.document.macroenabled.12": ".docm", 59 "application/vnd.ms-word.template.macroenabled.12": ".dotm", 60 "application/vnd.openxmlformats-officedocument.presentationml.template": ".potx", 61 "application/vnd.openxmlformats-officedocument.spreadsheetml.template": ".xltx", 62 "application/vnd.openxmlformats-officedocument.wordprocessingml.template": ".dotx", 63 "application/vnd.sun.xml.writer": ".sxw", 64 "text/richtext": ".rtf", 65 } 66 */ 67 68 // Load the example export formats into exportFormats for testing 69 func TestInternalLoadExampleFormats(t *testing.T) { 70 fetchFormatsOnce.Do(func() {}) 71 buf, err := ioutil.ReadFile(filepath.FromSlash("test/about.json")) 72 var about struct { 73 ExportFormats map[string][]string `json:"exportFormats,omitempty"` 74 ImportFormats map[string][]string `json:"importFormats,omitempty"` 75 } 76 require.NoError(t, err) 77 require.NoError(t, json.Unmarshal(buf, &about)) 78 _exportFormats = fixMimeTypeMap(about.ExportFormats) 79 _importFormats = fixMimeTypeMap(about.ImportFormats) 80 } 81 82 func TestInternalParseExtensions(t *testing.T) { 83 for _, test := range []struct { 84 in string 85 want []string 86 wantErr error 87 }{ 88 {"doc", []string{".doc"}, nil}, 89 {" docx ,XLSX, pptx,svg", []string{".docx", ".xlsx", ".pptx", ".svg"}, nil}, 90 {"docx,svg,Docx", []string{".docx", ".svg"}, nil}, 91 {"docx,potato,docx", []string{".docx"}, errors.New(`couldn't find MIME type for extension ".potato"`)}, 92 } { 93 extensions, _, gotErr := parseExtensions(test.in) 94 if test.wantErr == nil { 95 assert.NoError(t, gotErr) 96 } else { 97 assert.EqualError(t, gotErr, test.wantErr.Error()) 98 } 99 assert.Equal(t, test.want, extensions) 100 } 101 102 // Test it is appending 103 extensions, _, gotErr := parseExtensions("docx,svg", "docx,svg,xlsx") 104 assert.NoError(t, gotErr) 105 assert.Equal(t, []string{".docx", ".svg", ".xlsx"}, extensions) 106 } 107 108 func TestInternalFindExportFormat(t *testing.T) { 109 item := &drive.File{ 110 Name: "file", 111 MimeType: "application/vnd.google-apps.document", 112 } 113 for _, test := range []struct { 114 extensions []string 115 wantExtension string 116 wantMimeType string 117 }{ 118 {[]string{}, "", ""}, 119 {[]string{".pdf"}, ".pdf", "application/pdf"}, 120 {[]string{".pdf", ".rtf", ".xls"}, ".pdf", "application/pdf"}, 121 {[]string{".xls", ".rtf", ".pdf"}, ".rtf", "application/rtf"}, 122 {[]string{".xls", ".csv", ".svg"}, "", ""}, 123 } { 124 f := new(Fs) 125 f.exportExtensions = test.extensions 126 gotExtension, gotFilename, gotMimeType, gotIsDocument := f.findExportFormat(item) 127 assert.Equal(t, test.wantExtension, gotExtension) 128 if test.wantExtension != "" { 129 assert.Equal(t, item.Name+gotExtension, gotFilename) 130 } else { 131 assert.Equal(t, "", gotFilename) 132 } 133 assert.Equal(t, test.wantMimeType, gotMimeType) 134 assert.Equal(t, true, gotIsDocument) 135 } 136 } 137 138 func TestMimeTypesToExtension(t *testing.T) { 139 for mimeType, extension := range _mimeTypeToExtension { 140 extensions, err := mime.ExtensionsByType(mimeType) 141 assert.NoError(t, err) 142 assert.Contains(t, extensions, extension) 143 } 144 } 145 146 func TestExtensionToMimeType(t *testing.T) { 147 for mimeType, extension := range _mimeTypeToExtension { 148 gotMimeType := mime.TypeByExtension(extension) 149 mediatype, _, err := mime.ParseMediaType(gotMimeType) 150 assert.NoError(t, err) 151 assert.Equal(t, mimeType, mediatype) 152 } 153 } 154 155 func TestExtensionsForExportFormats(t *testing.T) { 156 if _exportFormats == nil { 157 t.Error("exportFormats == nil") 158 } 159 for fromMT, toMTs := range _exportFormats { 160 for _, toMT := range toMTs { 161 if !isInternalMimeType(toMT) { 162 extensions, err := mime.ExtensionsByType(toMT) 163 assert.NoError(t, err, "invalid MIME type %q", toMT) 164 assert.NotEmpty(t, extensions, "No extension found for %q (from: %q)", fromMT, toMT) 165 } 166 } 167 } 168 } 169 170 func TestExtensionsForImportFormats(t *testing.T) { 171 t.Skip() 172 if _importFormats == nil { 173 t.Error("_importFormats == nil") 174 } 175 for fromMT := range _importFormats { 176 if !isInternalMimeType(fromMT) { 177 extensions, err := mime.ExtensionsByType(fromMT) 178 assert.NoError(t, err, "invalid MIME type %q", fromMT) 179 assert.NotEmpty(t, extensions, "No extension found for %q", fromMT) 180 } 181 } 182 } 183 184 func (f *Fs) InternalTestDocumentImport(t *testing.T) { 185 oldAllow := f.opt.AllowImportNameChange 186 f.opt.AllowImportNameChange = true 187 defer func() { 188 f.opt.AllowImportNameChange = oldAllow 189 }() 190 191 testFilesPath, err := filepath.Abs(filepath.FromSlash("test/files")) 192 require.NoError(t, err) 193 194 testFilesFs, err := fs.NewFs(testFilesPath) 195 require.NoError(t, err) 196 197 _, f.importMimeTypes, err = parseExtensions("odt,ods,doc") 198 require.NoError(t, err) 199 200 err = operations.CopyFile(context.Background(), f, testFilesFs, "example2.doc", "example2.doc") 201 require.NoError(t, err) 202 } 203 204 func (f *Fs) InternalTestDocumentUpdate(t *testing.T) { 205 testFilesPath, err := filepath.Abs(filepath.FromSlash("test/files")) 206 require.NoError(t, err) 207 208 testFilesFs, err := fs.NewFs(testFilesPath) 209 require.NoError(t, err) 210 211 _, f.importMimeTypes, err = parseExtensions("odt,ods,doc") 212 require.NoError(t, err) 213 214 err = operations.CopyFile(context.Background(), f, testFilesFs, "example2.xlsx", "example1.ods") 215 require.NoError(t, err) 216 } 217 218 func (f *Fs) InternalTestDocumentExport(t *testing.T) { 219 var buf bytes.Buffer 220 var err error 221 222 f.exportExtensions, _, err = parseExtensions("txt") 223 require.NoError(t, err) 224 225 obj, err := f.NewObject(context.Background(), "example2.txt") 226 require.NoError(t, err) 227 228 rc, err := obj.Open(context.Background()) 229 require.NoError(t, err) 230 defer func() { require.NoError(t, rc.Close()) }() 231 232 _, err = io.Copy(&buf, rc) 233 require.NoError(t, err) 234 text := buf.String() 235 236 for _, excerpt := range []string{ 237 "Lorem ipsum dolor sit amet, consectetur", 238 "porta at ultrices in, consectetur at augue.", 239 } { 240 require.Contains(t, text, excerpt) 241 } 242 } 243 244 func (f *Fs) InternalTestDocumentLink(t *testing.T) { 245 var buf bytes.Buffer 246 var err error 247 248 f.exportExtensions, _, err = parseExtensions("link.html") 249 require.NoError(t, err) 250 251 obj, err := f.NewObject(context.Background(), "example2.link.html") 252 require.NoError(t, err) 253 254 rc, err := obj.Open(context.Background()) 255 require.NoError(t, err) 256 defer func() { require.NoError(t, rc.Close()) }() 257 258 _, err = io.Copy(&buf, rc) 259 require.NoError(t, err) 260 text := buf.String() 261 262 require.True(t, strings.HasPrefix(text, "<html>")) 263 require.True(t, strings.HasSuffix(text, "</html>\n")) 264 for _, excerpt := range []string{ 265 `<meta http-equiv="refresh"`, 266 `Loading <a href="`, 267 } { 268 require.Contains(t, text, excerpt) 269 } 270 } 271 272 // TestIntegration/FsMkdir/FsPutFiles/Internal/Shortcuts 273 func (f *Fs) InternalTestShortcuts(t *testing.T) { 274 const ( 275 // from fstest/fstests/fstests.go 276 existingDir = "hello? sausage" 277 existingFile = "file name.txt" 278 existingSubDir = "êé" 279 ) 280 ctx := context.Background() 281 srcObj, err := f.NewObject(ctx, existingFile) 282 require.NoError(t, err) 283 srcHash, err := srcObj.Hash(ctx, hash.MD5) 284 require.NoError(t, err) 285 assert.NotEqual(t, "", srcHash) 286 t.Run("Errors", func(t *testing.T) { 287 _, err := f.makeShortcut(ctx, "", f, "") 288 assert.Error(t, err) 289 assert.Contains(t, err.Error(), "can't be root") 290 291 _, err = f.makeShortcut(ctx, "notfound", f, "dst") 292 assert.Error(t, err) 293 assert.Contains(t, err.Error(), "can't find source") 294 295 _, err = f.makeShortcut(ctx, existingFile, f, existingFile) 296 assert.Error(t, err) 297 assert.Contains(t, err.Error(), "not overwriting") 298 assert.Contains(t, err.Error(), "existing file") 299 300 _, err = f.makeShortcut(ctx, existingFile, f, existingDir) 301 assert.Error(t, err) 302 assert.Contains(t, err.Error(), "not overwriting") 303 assert.Contains(t, err.Error(), "existing directory") 304 }) 305 t.Run("File", func(t *testing.T) { 306 dstObj, err := f.makeShortcut(ctx, existingFile, f, "shortcut.txt") 307 require.NoError(t, err) 308 require.NotNil(t, dstObj) 309 assert.Equal(t, "shortcut.txt", dstObj.Remote()) 310 dstHash, err := dstObj.Hash(ctx, hash.MD5) 311 require.NoError(t, err) 312 assert.Equal(t, srcHash, dstHash) 313 require.NoError(t, dstObj.Remove(ctx)) 314 }) 315 t.Run("Dir", func(t *testing.T) { 316 dstObj, err := f.makeShortcut(ctx, existingDir, f, "shortcutdir") 317 require.NoError(t, err) 318 require.Nil(t, dstObj) 319 entries, err := f.List(ctx, "shortcutdir") 320 require.NoError(t, err) 321 require.Equal(t, 1, len(entries)) 322 require.Equal(t, "shortcutdir/"+existingSubDir, entries[0].Remote()) 323 require.NoError(t, f.Rmdir(ctx, "shortcutdir")) 324 }) 325 t.Run("Command", func(t *testing.T) { 326 _, err := f.Command(ctx, "shortcut", []string{"one"}, nil) 327 require.Error(t, err) 328 require.Contains(t, err.Error(), "need exactly 2 arguments") 329 330 _, err = f.Command(ctx, "shortcut", []string{"one", "two"}, map[string]string{ 331 "target": "doesnotexistremote:", 332 }) 333 require.Error(t, err) 334 require.Contains(t, err.Error(), "couldn't find target") 335 336 _, err = f.Command(ctx, "shortcut", []string{"one", "two"}, map[string]string{ 337 "target": ".", 338 }) 339 require.Error(t, err) 340 require.Contains(t, err.Error(), "target is not a drive backend") 341 342 dstObjI, err := f.Command(ctx, "shortcut", []string{existingFile, "shortcut2.txt"}, map[string]string{ 343 "target": fs.ConfigString(f), 344 }) 345 require.NoError(t, err) 346 dstObj := dstObjI.(*Object) 347 assert.Equal(t, "shortcut2.txt", dstObj.Remote()) 348 dstHash, err := dstObj.Hash(ctx, hash.MD5) 349 require.NoError(t, err) 350 assert.Equal(t, srcHash, dstHash) 351 require.NoError(t, dstObj.Remove(ctx)) 352 353 dstObjI, err = f.Command(ctx, "shortcut", []string{existingFile, "shortcut3.txt"}, nil) 354 require.NoError(t, err) 355 dstObj = dstObjI.(*Object) 356 assert.Equal(t, "shortcut3.txt", dstObj.Remote()) 357 dstHash, err = dstObj.Hash(ctx, hash.MD5) 358 require.NoError(t, err) 359 assert.Equal(t, srcHash, dstHash) 360 require.NoError(t, dstObj.Remove(ctx)) 361 }) 362 } 363 364 func (f *Fs) InternalTest(t *testing.T) { 365 // These tests all depend on each other so run them as nested tests 366 t.Run("DocumentImport", func(t *testing.T) { 367 f.InternalTestDocumentImport(t) 368 t.Run("DocumentUpdate", func(t *testing.T) { 369 f.InternalTestDocumentUpdate(t) 370 t.Run("DocumentExport", func(t *testing.T) { 371 f.InternalTestDocumentExport(t) 372 t.Run("DocumentLink", func(t *testing.T) { 373 f.InternalTestDocumentLink(t) 374 }) 375 }) 376 }) 377 }) 378 t.Run("Shortcuts", f.InternalTestShortcuts) 379 } 380 381 var _ fstests.InternalTester = (*Fs)(nil)