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)