mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-11 05:06:51 +00:00
GODT-1332 Added tests for cache move functions.
This commit is contained in:
@ -27,24 +27,6 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (u *Users) EnableCache() error {
|
||||
// NOTE(GODT-1158): Check for available size before enabling.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Users) DisableCache() error {
|
||||
// NOTE(GODT-1158): Is it an error if we can't remove a user's cache?
|
||||
|
||||
for _, user := range u.users {
|
||||
if err := user.store.RemoveCache(); err != nil {
|
||||
logrus.WithError(err).Error("Failed to remove user's message cache")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isFolderEmpty checks whether a folder is empty.
|
||||
// path must point to an existing folder.
|
||||
func isFolderEmpty(path string) (bool, error) {
|
||||
@ -171,8 +153,13 @@ func copyFile(srcPath, dstPath string) error {
|
||||
}
|
||||
|
||||
dstInfo, err := os.Stat(dstPath)
|
||||
if err == nil && !dstInfo.Mode().IsRegular() {
|
||||
return errors.New("destination exists and is not a regular file")
|
||||
if err == nil {
|
||||
if !dstInfo.Mode().IsRegular() {
|
||||
return errors.New("destination exists and is not a regular file")
|
||||
}
|
||||
if os.SameFile(srcInfo, dstInfo) {
|
||||
return errors.New("source and destination are the same")
|
||||
}
|
||||
}
|
||||
|
||||
src, err := os.Open(filepath.Clean(srcPath))
|
||||
@ -194,6 +181,24 @@ func copyFile(srcPath, dstPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *Users) EnableCache() error {
|
||||
// NOTE(GODT-1158): Check for available size before enabling.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Users) DisableCache() error {
|
||||
// NOTE(GODT-1158): Is it an error if we can't remove a user's cache?
|
||||
|
||||
for _, user := range u.users {
|
||||
if err := user.store.RemoveCache(); err != nil {
|
||||
logrus.WithError(err).Error("Failed to remove user's message cache")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MigrateCache moves the message cache folder from folder srcPath to folder dstPath.
|
||||
// srcPath must point to an existing folder. dstPath must be an empty folder or not exist.
|
||||
func (u *Users) MigrateCache(srcPath, dstPath string) error {
|
||||
|
||||
192
internal/users/cache_test.go
Normal file
192
internal/users/cache_test.go
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
r "github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
str1 = "Lorem ipsum dolor sit amet"
|
||||
str2 = "consectetur adipisicing elit"
|
||||
)
|
||||
|
||||
// tempFileWithContent() creates a temporary file in folderPath containing the string content.
|
||||
// Returns the path of the created file.
|
||||
func tempFileWithContent(folderPath, content string) (string, error) {
|
||||
file, err := ioutil.TempFile(folderPath, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
_, err = file.WriteString(content)
|
||||
return file.Name(), err
|
||||
}
|
||||
|
||||
// itemCountInFolder() counts the number of items (files, folders, etc) in a folder.
|
||||
// Returns -1 if an error occurred.
|
||||
func itemCountInFolder(path string) int {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return len(files)
|
||||
}
|
||||
|
||||
// hashForFile returns the sha1 hash for the given file.
|
||||
func hashForFile(path string) (string, error) {
|
||||
hash := sha1.New()
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
if _, err = io.Copy(hash, file); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// filesAreIdentical() returns true if the two given files exist and have the same content.
|
||||
func filesAreIdentical(path1, path2 string) bool {
|
||||
hash1, err := hashForFile(path1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
hash2, err := hashForFile(path2)
|
||||
return (err == nil) && hash1 == hash2
|
||||
}
|
||||
|
||||
func TestCache_IsFolderEmpty(t *testing.T) {
|
||||
_, err := isFolderEmpty("")
|
||||
r.Error(t, err)
|
||||
tempDirPath, err := ioutil.TempDir("", "")
|
||||
defer func() { r.NoError(t, os.Remove(tempDirPath)) }()
|
||||
r.NoError(t, err)
|
||||
result, err := isFolderEmpty(tempDirPath)
|
||||
r.NoError(t, err)
|
||||
r.True(t, result)
|
||||
tempFile, err := ioutil.TempFile(tempDirPath, "")
|
||||
r.NoError(t, err)
|
||||
defer func() { r.NoError(t, os.Remove(tempFile.Name())) }()
|
||||
r.NoError(t, tempFile.Close())
|
||||
_, err = isFolderEmpty(tempFile.Name())
|
||||
r.Error(t, err)
|
||||
result, err = isFolderEmpty(tempDirPath)
|
||||
r.NoError(t, err)
|
||||
r.False(t, result)
|
||||
}
|
||||
|
||||
func TestCache_CheckFolderIsSuitableDestinationForCache(t *testing.T) {
|
||||
tempDirPath, err := ioutil.TempDir("", "")
|
||||
defer func() { _ = os.Remove(tempDirPath) }() // cleanup in case we fail before removing it.
|
||||
r.NoError(t, err)
|
||||
tempFile, err := ioutil.TempFile(tempDirPath, "")
|
||||
r.NoError(t, err)
|
||||
defer func() { _ = os.Remove(tempFile.Name()) }() // cleanup in case we fail before removing it.
|
||||
r.NoError(t, tempFile.Close())
|
||||
r.Error(t, checkFolderIsSuitableDestinationForCache(tempDirPath))
|
||||
r.NoError(t, os.Remove(tempFile.Name()))
|
||||
r.NoError(t, checkFolderIsSuitableDestinationForCache(tempDirPath))
|
||||
r.NoDirExists(t, tempDirPath) // previous call to checkFolderIsSuitableDestinationForCache should have removed the folder
|
||||
r.NoError(t, checkFolderIsSuitableDestinationForCache(tempDirPath))
|
||||
}
|
||||
|
||||
func TestCache_CopyFolder(t *testing.T) {
|
||||
// create a simple tree structure
|
||||
// srcDir/
|
||||
// |-file1
|
||||
// |-srcSubDir/
|
||||
// |-file2
|
||||
|
||||
srcDir, err := ioutil.TempDir("", "")
|
||||
defer func() { r.NoError(t, os.RemoveAll(srcDir)) }()
|
||||
r.NoError(t, err)
|
||||
srcSubDir, err := ioutil.TempDir(srcDir, "")
|
||||
r.NoError(t, err)
|
||||
subDirName := filepath.Base(srcSubDir)
|
||||
file1, err := tempFileWithContent(srcDir, str1)
|
||||
r.NoError(t, err)
|
||||
file2, err := tempFileWithContent(srcSubDir, str2)
|
||||
r.NoError(t, err)
|
||||
|
||||
// copy it
|
||||
dstDir := srcDir + "_"
|
||||
r.NoDirExists(t, dstDir)
|
||||
r.NoFileExists(t, dstDir)
|
||||
r.Error(t, copyFolder(srcDir, srcDir))
|
||||
r.NoError(t, copyFolder(srcDir, dstDir))
|
||||
defer func() { r.NoError(t, os.RemoveAll(dstDir)) }()
|
||||
|
||||
// check copy and original
|
||||
r.DirExists(t, srcDir)
|
||||
r.DirExists(t, srcSubDir)
|
||||
r.FileExists(t, file1)
|
||||
r.FileExists(t, file2)
|
||||
r.True(t, itemCountInFolder(srcDir) == 2)
|
||||
r.True(t, itemCountInFolder(srcSubDir) == 1)
|
||||
r.DirExists(t, dstDir)
|
||||
dstSubDir := filepath.Join(dstDir, subDirName)
|
||||
r.DirExists(t, dstSubDir)
|
||||
dstFile1 := filepath.Join(dstDir, filepath.Base(file1))
|
||||
r.FileExists(t, dstFile1)
|
||||
dstFile2 := filepath.Join(dstDir, subDirName, filepath.Base(file2))
|
||||
r.FileExists(t, dstFile2)
|
||||
r.True(t, itemCountInFolder(dstDir) == 2)
|
||||
r.True(t, itemCountInFolder(dstSubDir) == 1)
|
||||
r.True(t, filesAreIdentical(file1, dstFile1))
|
||||
r.True(t, filesAreIdentical(file2, dstFile2))
|
||||
}
|
||||
|
||||
func TestCache_IsSubfolderOf(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
defer func() { r.NoError(t, os.Remove(dir)) }()
|
||||
r.NoError(t, err)
|
||||
r.True(t, isSubfolderOf(dir, dir))
|
||||
fakeDir := dir + "_"
|
||||
r.False(t, isSubfolderOf(dir, fakeDir+"_"))
|
||||
subDir := filepath.Join(dir, "A", "B")
|
||||
r.True(t, isSubfolderOf(subDir, dir))
|
||||
r.True(t, isSubfolderOf(filepath.Dir(subDir), dir))
|
||||
r.False(t, isSubfolderOf(dir, subDir))
|
||||
}
|
||||
|
||||
func TestCache_CopyFile(t *testing.T) {
|
||||
file1, err := tempFileWithContent("", str1)
|
||||
r.NoError(t, err)
|
||||
defer func() { r.NoError(t, os.Remove(file1)) }()
|
||||
file2, err := tempFileWithContent("", str2)
|
||||
r.NoError(t, err)
|
||||
defer func() { r.NoError(t, os.Remove(file2)) }()
|
||||
r.Error(t, copyFile(file1, file1))
|
||||
r.Error(t, copyFile(file1, filepath.Dir(file1)))
|
||||
r.Error(t, copyFile(file1, file1))
|
||||
r.NoError(t, copyFile(file1, file2))
|
||||
file3 := file2 + "_"
|
||||
r.NoFileExists(t, file3)
|
||||
r.NoError(t, copyFile(file1, file3))
|
||||
defer func() { r.NoError(t, os.Remove(file3)) }()
|
||||
}
|
||||
Reference in New Issue
Block a user