mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-11-29 22:08:10 +02:00
Please note that if the upload bandwidth between the SFTP client and SFTPGo is greater than the upload bandwidth between SFTPGo and S3 then the SFTP client have to wait for the upload of the last parts to S3 after it ends the file upload to SFTPGo, and it may time out. Keep this in mind if you customize parts size and upload concurrency
2372 lines
84 KiB
Go
2372 lines
84 KiB
Go
package httpd_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"mime/multipart"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-chi/render"
|
|
_ "github.com/go-sql-driver/mysql"
|
|
_ "github.com/lib/pq"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/drakkan/sftpgo/config"
|
|
"github.com/drakkan/sftpgo/dataprovider"
|
|
"github.com/drakkan/sftpgo/httpd"
|
|
"github.com/drakkan/sftpgo/logger"
|
|
"github.com/drakkan/sftpgo/sftpd"
|
|
"github.com/drakkan/sftpgo/utils"
|
|
"github.com/drakkan/sftpgo/vfs"
|
|
)
|
|
|
|
const (
|
|
defaultUsername = "test_user"
|
|
defaultPassword = "test_password"
|
|
testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
|
|
logSender = "APITesting"
|
|
userPath = "/api/v1/user"
|
|
activeConnectionsPath = "/api/v1/connection"
|
|
quotaScanPath = "/api/v1/quota_scan"
|
|
versionPath = "/api/v1/version"
|
|
providerStatusPath = "/api/v1/providerstatus"
|
|
dumpDataPath = "/api/v1/dumpdata"
|
|
loadDataPath = "/api/v1/loaddata"
|
|
metricsPath = "/metrics"
|
|
webBasePath = "/web"
|
|
webUsersPath = "/web/users"
|
|
webUserPath = "/web/user"
|
|
webConnectionsPath = "/web/connections"
|
|
configDir = ".."
|
|
httpsCert = `-----BEGIN CERTIFICATE-----
|
|
MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
|
|
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
|
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
|
|
OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
|
|
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
|
|
IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
|
|
NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
|
|
3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
|
|
GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
|
|
SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
|
|
/8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
|
|
dV4vKmHUzwK/eIx+8Ay3neE=
|
|
-----END CERTIFICATE-----`
|
|
httpsKey = `-----BEGIN EC PARAMETERS-----
|
|
BgUrgQQAIg==
|
|
-----END EC PARAMETERS-----
|
|
-----BEGIN EC PRIVATE KEY-----
|
|
MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
|
|
UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
|
|
WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
|
|
CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
|
|
-----END EC PRIVATE KEY-----`
|
|
)
|
|
|
|
var (
|
|
defaultPerms = []string{dataprovider.PermAny}
|
|
homeBasePath string
|
|
backupsPath string
|
|
credentialsPath string
|
|
testServer *httptest.Server
|
|
providerDriverName string
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
homeBasePath = os.TempDir()
|
|
logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
|
|
logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf := config.GetProviderConf()
|
|
credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
|
|
providerConf.CredentialsPath = credentialsPath
|
|
providerDriverName = providerConf.Driver
|
|
os.RemoveAll(credentialsPath)
|
|
|
|
err := dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
logger.Warn(logSender, "", "error initializing data provider: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
dataProvider := dataprovider.GetProvider()
|
|
httpdConf := config.GetHTTPDConfig()
|
|
|
|
httpdConf.BindPort = 8081
|
|
httpd.SetBaseURLAndCredentials("http://127.0.0.1:8081", "", "")
|
|
backupsPath = filepath.Join(os.TempDir(), "test_backups")
|
|
httpdConf.BackupsPath = backupsPath
|
|
os.MkdirAll(backupsPath, 0777)
|
|
|
|
sftpd.SetDataProvider(dataProvider)
|
|
httpd.SetDataProvider(dataProvider)
|
|
|
|
go func() {
|
|
if err := httpdConf.Initialize(configDir); err != nil {
|
|
logger.Error(logSender, "", "could not start HTTP server: %v", err)
|
|
}
|
|
}()
|
|
|
|
waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
|
|
// now start an https server
|
|
certPath := filepath.Join(os.TempDir(), "test.crt")
|
|
keyPath := filepath.Join(os.TempDir(), "test.key")
|
|
ioutil.WriteFile(certPath, []byte(httpsCert), 0666)
|
|
ioutil.WriteFile(keyPath, []byte(httpsKey), 0666)
|
|
httpdConf.BindPort = 8443
|
|
httpdConf.CertificateFile = certPath
|
|
httpdConf.CertificateKeyFile = keyPath
|
|
|
|
go func() {
|
|
if err := httpdConf.Initialize(configDir); err != nil {
|
|
logger.Error(logSender, "", "could not start HTTPS server: %v", err)
|
|
}
|
|
}()
|
|
waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
|
|
httpd.ReloadTLSCertificate()
|
|
|
|
testServer = httptest.NewServer(httpd.GetHTTPRouter())
|
|
defer testServer.Close()
|
|
|
|
exitCode := m.Run()
|
|
os.Remove(logfilePath)
|
|
os.RemoveAll(backupsPath)
|
|
os.RemoveAll(credentialsPath)
|
|
os.Remove(certPath)
|
|
os.Remove(keyPath)
|
|
os.Exit(exitCode)
|
|
}
|
|
|
|
func TestInitialization(t *testing.T) {
|
|
config.LoadConfig(configDir, "")
|
|
httpdConf := config.GetHTTPDConfig()
|
|
httpdConf.BackupsPath = "test_backups"
|
|
httpdConf.AuthUserFile = "invalid file"
|
|
err := httpdConf.Initialize(configDir)
|
|
if err == nil {
|
|
t.Error("Inizialize must fail")
|
|
}
|
|
httpdConf.BackupsPath = backupsPath
|
|
httpdConf.AuthUserFile = ""
|
|
httpdConf.CertificateFile = "invalid file"
|
|
httpdConf.CertificateKeyFile = "invalid file"
|
|
err = httpdConf.Initialize(configDir)
|
|
if err == nil {
|
|
t.Error("Inizialize must fail")
|
|
}
|
|
httpdConf.CertificateFile = ""
|
|
httpdConf.CertificateKeyFile = ""
|
|
httpdConf.TemplatesPath = "."
|
|
err = httpdConf.Initialize(configDir)
|
|
if err == nil {
|
|
t.Error("Inizialize must fail")
|
|
}
|
|
}
|
|
|
|
func TestBasicUserHandling(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.MaxSessions = 10
|
|
user.QuotaSize = 4096
|
|
user.QuotaFiles = 2
|
|
user.UploadBandwidth = 128
|
|
user.DownloadBandwidth = 64
|
|
user.ExpirationDate = utils.GetTimeAsMsSinceEpoch(time.Now())
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("number of users mismatch, expected: 1, actual: %v", len(users))
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUserStatus(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Status = 3
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with bad status: %v", err)
|
|
}
|
|
u.Status = 0
|
|
user, _, err := httpd.AddUser(u, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.Status = 2
|
|
_, _, err = httpd.UpdateUser(user, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error updating user with bad status: %v", err)
|
|
}
|
|
user.Status = 1
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserNoCredentials(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Password = ""
|
|
u.PublicKeys = []string{}
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no credentials: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserNoUsername(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Username = ""
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no home dir: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserNoHomeDir(t *testing.T) {
|
|
u := getTestUser()
|
|
u.HomeDir = ""
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no home dir: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserInvalidHomeDir(t *testing.T) {
|
|
u := getTestUser()
|
|
u.HomeDir = "relative_path"
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid home dir: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserNoPerms(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Permissions = make(map[string][]string)
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no perms: %v", err)
|
|
}
|
|
u.Permissions["/"] = []string{}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no perms: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserInvalidPerms(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Permissions["/"] = []string{"invalidPerm"}
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid perms: %v", err)
|
|
}
|
|
// permissions for root dir are mandatory
|
|
u.Permissions["/"] = []string{}
|
|
u.Permissions["/somedir"] = []string{dataprovider.PermAny}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with no root dir perms: %v", err)
|
|
}
|
|
u.Permissions["/"] = []string{dataprovider.PermAny}
|
|
u.Permissions["/subdir/.."] = []string{dataprovider.PermAny}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid dir perms: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserInvalidFilters(t *testing.T) {
|
|
u := getTestUser()
|
|
u.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0"}
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid filters: %v", err)
|
|
}
|
|
u.Filters.AllowedIP = []string{}
|
|
u.Filters.DeniedIP = []string{"192.168.3.0/16", "invalid"}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid filters: %v", err)
|
|
}
|
|
u.Filters.DeniedIP = []string{}
|
|
u.Filters.DeniedLoginMethods = []string{"invalid"}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid filters: %v", err)
|
|
}
|
|
u.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodKeyboardInteractive,
|
|
dataprovider.SSHLoginMethodPassword, dataprovider.SSHLoginMethodPublicKey}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid filters: %v", err)
|
|
}
|
|
u.Filters.DeniedLoginMethods = []string{}
|
|
u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
|
|
{
|
|
Path: "relative",
|
|
AllowedExtensions: []string{},
|
|
DeniedExtensions: []string{},
|
|
},
|
|
}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid extensions filters: %v", err)
|
|
}
|
|
u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
|
|
{
|
|
Path: "/",
|
|
AllowedExtensions: []string{},
|
|
DeniedExtensions: []string{},
|
|
},
|
|
}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid extensions filters: %v", err)
|
|
}
|
|
u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
|
|
{
|
|
Path: "/subdir",
|
|
AllowedExtensions: []string{".zip"},
|
|
DeniedExtensions: []string{},
|
|
},
|
|
{
|
|
Path: "/subdir",
|
|
AllowedExtensions: []string{".rar"},
|
|
DeniedExtensions: []string{".jpg"},
|
|
},
|
|
}
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid extensions filters: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserInvalidFsConfig(t *testing.T) {
|
|
u := getTestUser()
|
|
u.FsConfig.Provider = 1
|
|
u.FsConfig.S3Config.Bucket = ""
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
os.RemoveAll(credentialsPath)
|
|
os.MkdirAll(credentialsPath, 0700)
|
|
u.FsConfig.S3Config.Bucket = "test"
|
|
u.FsConfig.S3Config.Region = "eu-west-1"
|
|
u.FsConfig.S3Config.AccessKey = "access-key"
|
|
u.FsConfig.S3Config.AccessSecret = "access-secret"
|
|
u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
|
|
u.FsConfig.S3Config.StorageClass = "Standard"
|
|
u.FsConfig.S3Config.KeyPrefix = "/somedir/subdir/"
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u.FsConfig.S3Config.KeyPrefix = ""
|
|
u.FsConfig.S3Config.UploadPartSize = 3
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u.FsConfig.S3Config.UploadPartSize = 0
|
|
u.FsConfig.S3Config.UploadConcurrency = -1
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u = getTestUser()
|
|
u.FsConfig.Provider = 2
|
|
u.FsConfig.GCSConfig.Bucket = ""
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u.FsConfig.GCSConfig.Bucket = "test"
|
|
u.FsConfig.GCSConfig.StorageClass = "Standard"
|
|
u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
|
|
u.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("test"))
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
|
|
u.FsConfig.GCSConfig.Credentials = ""
|
|
u.FsConfig.GCSConfig.AutomaticCredentials = 0
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
u.FsConfig.GCSConfig.Credentials = "no base64 encoded"
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid fs config: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddUserInvalidVirtualFolders(t *testing.T) {
|
|
u := getTestUser()
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "vdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir",
|
|
MappedPath: filepath.Join(u.GetHomeDir(), "mapped_dir"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir",
|
|
MappedPath: u.GetHomeDir(),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir",
|
|
MappedPath: filepath.Join(u.GetHomeDir(), ".."),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir2",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir", "subdir"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir2",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir2",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir", "subdir"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1/subdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1/../vdir1",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir2"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
u.VirtualFolders = nil
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1/",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
|
|
})
|
|
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1/subdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir2"),
|
|
})
|
|
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid virtual folder: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUserPublicKey(t *testing.T) {
|
|
u := getTestUser()
|
|
invalidPubKey := "invalid"
|
|
validPubKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
|
|
u.PublicKeys = []string{invalidPubKey}
|
|
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error adding user with invalid pub key: %v", err)
|
|
}
|
|
u.PublicKeys = []string{validPubKey}
|
|
user, _, err := httpd.AddUser(u, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.PublicKeys = []string{validPubKey, invalidPubKey}
|
|
_, _, err = httpd.UpdateUser(user, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("update user with invalid public key must fail: %v", err)
|
|
}
|
|
user.PublicKeys = []string{validPubKey, validPubKey, validPubKey}
|
|
_, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateUser(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.HomeDir = filepath.Join(homeBasePath, "testmod")
|
|
user.UID = 33
|
|
user.GID = 101
|
|
user.MaxSessions = 10
|
|
user.QuotaSize = 4096
|
|
user.QuotaFiles = 2
|
|
user.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermDelete, dataprovider.PermDownload}
|
|
user.Permissions["/subdir"] = []string{dataprovider.PermListItems, dataprovider.PermUpload}
|
|
user.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0/24"}
|
|
user.Filters.DeniedIP = []string{"192.168.3.0/24", "192.168.4.0/24"}
|
|
user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPassword}
|
|
user.Filters.FileExtensions = append(user.Filters.FileExtensions, dataprovider.ExtensionsFilter{
|
|
Path: "/subdir",
|
|
AllowedExtensions: []string{".zip", ".rar"},
|
|
DeniedExtensions: []string{".jpg", ".png"},
|
|
})
|
|
user.UploadBandwidth = 1024
|
|
user.DownloadBandwidth = 512
|
|
user.VirtualFolders = nil
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir1",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
VirtualPath: "/vdir12/subdir",
|
|
MappedPath: filepath.Join(os.TempDir(), "mapped_dir2"),
|
|
})
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
user.Permissions["/subdir"] = []string{}
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
if len(user.Permissions["/subdir"]) > 0 {
|
|
t.Errorf("unexpected subdir permissions, must be empty")
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUserS3Config(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 1
|
|
user.FsConfig.S3Config.Bucket = "test"
|
|
user.FsConfig.S3Config.Region = "us-east-1"
|
|
user.FsConfig.S3Config.AccessKey = "Server-Access-Key"
|
|
user.FsConfig.S3Config.AccessSecret = "Server-Access-Secret"
|
|
user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000"
|
|
user.FsConfig.S3Config.UploadPartSize = 8
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
user.Password = defaultPassword
|
|
user.ID = 0
|
|
secret, _ := utils.EncryptData("Server-Access-Secret")
|
|
user.FsConfig.S3Config.AccessSecret = secret
|
|
user, _, err = httpd.AddUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 1
|
|
user.FsConfig.S3Config.Bucket = "test1"
|
|
user.FsConfig.S3Config.Region = "us-east-1"
|
|
user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
|
|
user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
|
|
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
|
|
user.FsConfig.S3Config.UploadConcurrency = 5
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 0
|
|
user.FsConfig.S3Config.Bucket = ""
|
|
user.FsConfig.S3Config.Region = ""
|
|
user.FsConfig.S3Config.AccessKey = ""
|
|
user.FsConfig.S3Config.AccessSecret = ""
|
|
user.FsConfig.S3Config.Endpoint = ""
|
|
user.FsConfig.S3Config.KeyPrefix = ""
|
|
user.FsConfig.S3Config.UploadPartSize = 0
|
|
user.FsConfig.S3Config.UploadConcurrency = 0
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
// test user without access key and access secret (shared config state)
|
|
user.FsConfig.Provider = 1
|
|
user.FsConfig.S3Config.Bucket = "test1"
|
|
user.FsConfig.S3Config.Region = "us-east-1"
|
|
user.FsConfig.S3Config.AccessKey = ""
|
|
user.FsConfig.S3Config.AccessSecret = ""
|
|
user.FsConfig.S3Config.Endpoint = ""
|
|
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
|
|
user.FsConfig.S3Config.UploadPartSize = 6
|
|
user.FsConfig.S3Config.UploadConcurrency = 4
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUserGCSConfig(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
os.RemoveAll(credentialsPath)
|
|
os.MkdirAll(credentialsPath, 0700)
|
|
user.FsConfig.Provider = 2
|
|
user.FsConfig.GCSConfig.Bucket = "test"
|
|
user.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("fake credentials"))
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
user.Password = defaultPassword
|
|
user.ID = 0
|
|
// the user will be added since the credentials file is found
|
|
user, _, err = httpd.AddUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
os.RemoveAll(credentialsPath)
|
|
os.MkdirAll(credentialsPath, 0700)
|
|
user.FsConfig.GCSConfig.Credentials = ""
|
|
user.FsConfig.GCSConfig.AutomaticCredentials = 1
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 1
|
|
user.FsConfig.S3Config.Bucket = "test1"
|
|
user.FsConfig.S3Config.Region = "us-east-1"
|
|
user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
|
|
user.FsConfig.S3Config.AccessSecret = "secret"
|
|
user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
|
|
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 2
|
|
user.FsConfig.GCSConfig.Bucket = "test1"
|
|
user.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("fake credentials"))
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateUserNoCredentials(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.Password = ""
|
|
user.PublicKeys = []string{}
|
|
// password and public key will be omitted from json serialization if empty and so they will remain unchanged
|
|
// and no validation error will be raised
|
|
_, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error updating user with no credentials: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateUserEmptyHomeDir(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.HomeDir = ""
|
|
_, _, err = httpd.UpdateUser(user, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error updating user with empty home dir: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateUserInvalidHomeDir(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
user.HomeDir = "relative_path"
|
|
_, _, err = httpd.UpdateUser(user, http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error updating user with empty home dir: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateNonExistentUser(t *testing.T) {
|
|
_, _, err := httpd.UpdateUser(getTestUser(), http.StatusNotFound)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetNonExistentUser(t *testing.T) {
|
|
_, _, err := httpd.GetUserByID(0, http.StatusNotFound)
|
|
if err != nil {
|
|
t.Errorf("unable to get user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteNonExistentUser(t *testing.T) {
|
|
_, err := httpd.RemoveUser(getTestUser(), http.StatusNotFound)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddDuplicateUser(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
_, _, err = httpd.AddUser(getTestUser(), http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("unable to add second user: %v", err)
|
|
}
|
|
_, _, err = httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err == nil {
|
|
t.Errorf("adding a duplicate user must fail")
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetUsers(t *testing.T) {
|
|
user1, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
u := getTestUser()
|
|
u.Username = defaultUsername + "1"
|
|
user2, _, err := httpd.AddUser(u, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add second user: %v", err)
|
|
}
|
|
users, _, err := httpd.GetUsers(0, 0, "", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) < 2 {
|
|
t.Errorf("at least 2 users are expected")
|
|
}
|
|
users, _, err = httpd.GetUsers(1, 0, "", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
users, _, err = httpd.GetUsers(1, 1, "", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
_, _, err = httpd.GetUsers(1, 1, "", http.StatusInternalServerError)
|
|
if err == nil {
|
|
t.Errorf("get users must succeed, we requested a fail for a good request")
|
|
}
|
|
_, err = httpd.RemoveUser(user1, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user2, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetQuotaScans(t *testing.T) {
|
|
_, _, err := httpd.GetQuotaScans(http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get quota scans: %v", err)
|
|
}
|
|
_, _, err = httpd.GetQuotaScans(http.StatusInternalServerError)
|
|
if err == nil {
|
|
t.Errorf("quota scan request must succeed, we requested to check a wrong status code")
|
|
}
|
|
}
|
|
|
|
func TestStartQuotaScan(t *testing.T) {
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
_, err = httpd.StartQuotaScan(user, http.StatusCreated)
|
|
if err != nil {
|
|
t.Errorf("unable to start quota scan: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetVersion(t *testing.T) {
|
|
_, _, err := httpd.GetVersion(http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get version: %v", err)
|
|
}
|
|
_, _, err = httpd.GetVersion(http.StatusInternalServerError)
|
|
if err == nil {
|
|
t.Errorf("get version request must succeed, we requested to check a wrong status code")
|
|
}
|
|
}
|
|
|
|
func TestGetProviderStatus(t *testing.T) {
|
|
_, _, err := httpd.GetProviderStatus(http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get provider status: %v", err)
|
|
}
|
|
_, _, err = httpd.GetProviderStatus(http.StatusBadRequest)
|
|
if err == nil {
|
|
t.Errorf("get provider status request must succeed, we requested to check a wrong status code")
|
|
}
|
|
}
|
|
|
|
func TestGetConnections(t *testing.T) {
|
|
_, _, err := httpd.GetConnections(http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get sftp connections: %v", err)
|
|
}
|
|
_, _, err = httpd.GetConnections(http.StatusInternalServerError)
|
|
if err == nil {
|
|
t.Errorf("get sftp connections request must succeed, we requested to check a wrong status code")
|
|
}
|
|
}
|
|
|
|
func TestCloseActiveConnection(t *testing.T) {
|
|
_, err := httpd.CloseConnection("non_existent_id", http.StatusNotFound)
|
|
if err != nil {
|
|
t.Errorf("unexpected error closing non existent sftp connection: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUserBaseDir(t *testing.T) {
|
|
dataProvider := dataprovider.GetProvider()
|
|
dataprovider.Close(dataProvider)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf := config.GetProviderConf()
|
|
providerConf.UsersBaseDir = homeBasePath
|
|
err := dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider with users base dir")
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
u := getTestUser()
|
|
u.HomeDir = ""
|
|
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to add user: %v", err)
|
|
}
|
|
if user.HomeDir != filepath.Join(providerConf.UsersBaseDir, u.Username) {
|
|
t.Errorf("invalid home dir: %v", user.HomeDir)
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove: %v", err)
|
|
}
|
|
dataProvider = dataprovider.GetProvider()
|
|
dataprovider.Close(dataProvider)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf = config.GetProviderConf()
|
|
providerConf.CredentialsPath = credentialsPath
|
|
os.RemoveAll(credentialsPath)
|
|
err = dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider")
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
sftpd.SetDataProvider(dataprovider.GetProvider())
|
|
}
|
|
|
|
func TestProviderErrors(t *testing.T) {
|
|
if providerDriverName == dataprovider.BoltDataProviderName {
|
|
t.Skip("skipping test provider errors for bolt provider")
|
|
}
|
|
dataProvider := dataprovider.GetProvider()
|
|
dataprovider.Close(dataProvider)
|
|
_, _, err := httpd.GetUserByID(0, http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("get user with provider closed must fail: %v", err)
|
|
}
|
|
_, _, err = httpd.GetUsers(1, 0, defaultUsername, http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("get users with provider closed must fail: %v", err)
|
|
}
|
|
_, _, err = httpd.UpdateUser(dataprovider.User{}, http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("update user with provider closed must fail: %v", err)
|
|
}
|
|
_, err = httpd.RemoveUser(dataprovider.User{}, http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("delete user with provider closed must fail: %v", err)
|
|
}
|
|
_, _, err = httpd.GetProviderStatus(http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("get provider status with provider closed must fail: %v", err)
|
|
}
|
|
_, _, err = httpd.Dumpdata("backup.json", "", http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("get provider status with provider closed must fail: %v", err)
|
|
}
|
|
user := getTestUser()
|
|
user.ID = 1
|
|
backupData := dataprovider.BackupData{}
|
|
backupData.Users = append(backupData.Users, user)
|
|
backupContent, _ := json.Marshal(backupData)
|
|
backupFilePath := filepath.Join(backupsPath, "backup.json")
|
|
ioutil.WriteFile(backupFilePath, backupContent, 0666)
|
|
_, _, err = httpd.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("get provider status with provider closed must fail: %v", err)
|
|
}
|
|
os.Remove(backupFilePath)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf := config.GetProviderConf()
|
|
providerConf.CredentialsPath = credentialsPath
|
|
os.RemoveAll(credentialsPath)
|
|
err = dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider")
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
sftpd.SetDataProvider(dataprovider.GetProvider())
|
|
}
|
|
|
|
func TestDumpdata(t *testing.T) {
|
|
dataProvider := dataprovider.GetProvider()
|
|
dataprovider.Close(dataProvider)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf := config.GetProviderConf()
|
|
err := dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider")
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
sftpd.SetDataProvider(dataprovider.GetProvider())
|
|
_, _, err = httpd.Dumpdata("", "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Dumpdata(filepath.Join(backupsPath, "backup.json"), "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Dumpdata("../backup.json", "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Dumpdata("backup.json", "0", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Dumpdata("backup.json", "1", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
os.Remove(filepath.Join(backupsPath, "backup.json"))
|
|
if runtime.GOOS != "windows" {
|
|
os.Chmod(backupsPath, 0001)
|
|
_, _, err = httpd.Dumpdata("bck.json", "", http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
os.Chmod(backupsPath, 0755)
|
|
}
|
|
providerConf = config.GetProviderConf()
|
|
providerConf.CredentialsPath = credentialsPath
|
|
os.RemoveAll(credentialsPath)
|
|
err = dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider: %v", err)
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
sftpd.SetDataProvider(dataprovider.GetProvider())
|
|
}
|
|
|
|
func TestLoaddata(t *testing.T) {
|
|
user := getTestUser()
|
|
user.ID = 1
|
|
user.Username = "test_user_restore"
|
|
backupData := dataprovider.BackupData{}
|
|
backupData.Users = append(backupData.Users, user)
|
|
backupContent, _ := json.Marshal(backupData)
|
|
backupFilePath := filepath.Join(backupsPath, "backup.json")
|
|
ioutil.WriteFile(backupFilePath, backupContent, 0666)
|
|
_, _, err := httpd.Loaddata(backupFilePath, "a", "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Loaddata(backupFilePath, "", "a", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Loaddata("backup.json", "1", "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
_, _, err = httpd.Loaddata(backupFilePath+"a", "1", "", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if runtime.GOOS != "windows" {
|
|
os.Chmod(backupFilePath, 0111)
|
|
_, _, err = httpd.Loaddata(backupFilePath, "1", "", http.StatusInternalServerError)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
os.Chmod(backupFilePath, 0644)
|
|
}
|
|
// add user from backup
|
|
_, _, err = httpd.Loaddata(backupFilePath, "1", "", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
// update user from backup
|
|
_, _, err = httpd.Loaddata(backupFilePath, "2", "", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
users, _, err := httpd.GetUsers(1, 0, user.Username, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Error("Unable to get restored user")
|
|
}
|
|
user = users[0]
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
os.Remove(backupFilePath)
|
|
createTestFile(backupFilePath, 10485761)
|
|
_, _, err = httpd.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
os.Remove(backupFilePath)
|
|
createTestFile(backupFilePath, 65535)
|
|
_, _, err = httpd.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
os.Remove(backupFilePath)
|
|
}
|
|
|
|
func TestLoaddataMode(t *testing.T) {
|
|
user := getTestUser()
|
|
user.ID = 1
|
|
user.Username = "test_user_restore"
|
|
backupData := dataprovider.BackupData{}
|
|
backupData.Users = append(backupData.Users, user)
|
|
backupContent, _ := json.Marshal(backupData)
|
|
backupFilePath := filepath.Join(backupsPath, "backup.json")
|
|
ioutil.WriteFile(backupFilePath, backupContent, 0666)
|
|
_, _, err := httpd.Loaddata(backupFilePath, "0", "0", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
users, _, err := httpd.GetUsers(1, 0, user.Username, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Error("Unable to get restored user")
|
|
}
|
|
user = users[0]
|
|
oldUploadBandwidth := user.UploadBandwidth
|
|
user.UploadBandwidth = oldUploadBandwidth + 128
|
|
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to update user: %v", err)
|
|
}
|
|
_, _, err = httpd.Loaddata(backupFilePath, "0", "1", http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
users, _, err = httpd.GetUsers(1, 0, user.Username, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to get users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Error("Unable to get restored user")
|
|
}
|
|
user = users[0]
|
|
if user.UploadBandwidth == oldUploadBandwidth {
|
|
t.Error("user must not be modified")
|
|
}
|
|
_, err = httpd.RemoveUser(user, http.StatusOK)
|
|
if err != nil {
|
|
t.Errorf("unable to remove user: %v", err)
|
|
}
|
|
os.Remove(backupFilePath)
|
|
}
|
|
|
|
func TestHTTPSConnection(t *testing.T) {
|
|
client := &http.Client{
|
|
Timeout: 5 * time.Second,
|
|
}
|
|
_, err := client.Get("https://localhost:8443" + metricsPath)
|
|
if err == nil || (!strings.Contains(err.Error(), "certificate is not valid") &&
|
|
!strings.Contains(err.Error(), "certificate signed by unknown authority")) {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
// test using mock http server
|
|
|
|
func TestBasicUserHandlingMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
|
|
user.MaxSessions = 10
|
|
user.UploadBandwidth = 128
|
|
user.Permissions["/"] = []string{dataprovider.PermAny, dataprovider.PermDelete, dataprovider.PermDownload}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
|
|
var updatedUser dataprovider.User
|
|
err = render.DecodeJSON(rr.Body, &updatedUser)
|
|
if err != nil {
|
|
t.Errorf("Error decoding updated user: %v", err)
|
|
}
|
|
if user.MaxSessions != updatedUser.MaxSessions || user.UploadBandwidth != updatedUser.UploadBandwidth {
|
|
t.Errorf("Error modifying user actual: %v, %v", updatedUser.MaxSessions, updatedUser.UploadBandwidth)
|
|
}
|
|
if len(updatedUser.Permissions["/"]) != 1 {
|
|
t.Errorf("permissions other than any should be removed")
|
|
}
|
|
if !utils.IsStringInSlice(dataprovider.PermAny, updatedUser.Permissions["/"]) {
|
|
t.Errorf("permissions mismatch")
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestGetUserByIdInvalidParamsMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, userPath+"/0", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"/a", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestAddUserNoUsernameMock(t *testing.T) {
|
|
user := getTestUser()
|
|
user.Username = ""
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestAddUserInvalidHomeDirMock(t *testing.T) {
|
|
user := getTestUser()
|
|
user.HomeDir = "relative_path"
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestAddUserInvalidPermsMock(t *testing.T) {
|
|
user := getTestUser()
|
|
user.Permissions["/"] = []string{}
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestAddUserInvalidJsonMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer([]byte("invalid json")))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestUpdateUserMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
// permissions should not change if empty or nil
|
|
permissions := user.Permissions
|
|
user.Permissions = make(map[string][]string)
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var updatedUser dataprovider.User
|
|
err = render.DecodeJSON(rr.Body, &updatedUser)
|
|
if err != nil {
|
|
t.Errorf("Error decoding updated user: %v", err)
|
|
}
|
|
for dir, perms := range permissions {
|
|
if actualPerms, ok := updatedUser.Permissions[dir]; ok {
|
|
for _, v := range actualPerms {
|
|
if !utils.IsStringInSlice(v, perms) {
|
|
t.Error("Permissions contents mismatch")
|
|
}
|
|
}
|
|
} else {
|
|
t.Error("Permissions directories mismatch")
|
|
}
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestUserPermissionsMock(t *testing.T) {
|
|
user := getTestUser()
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/somedir"] = []string{dataprovider.PermAny}
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions[".."] = []string{dataprovider.PermAny}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
user.Permissions["/somedir"] = []string{"invalid"}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
delete(user.Permissions, "/somedir")
|
|
user.Permissions["/somedir/.."] = []string{dataprovider.PermAny}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
delete(user.Permissions, "/somedir/..")
|
|
user.Permissions["not_abs_path"] = []string{dataprovider.PermAny}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
delete(user.Permissions, "not_abs_path")
|
|
user.Permissions["/somedir/../otherdir/"] = []string{dataprovider.PermListItems}
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var updatedUser dataprovider.User
|
|
err = render.DecodeJSON(rr.Body, &updatedUser)
|
|
if err != nil {
|
|
t.Errorf("Error decoding updated user: %v", err)
|
|
}
|
|
if val, ok := updatedUser.Permissions["/otherdir"]; ok {
|
|
if !utils.IsStringInSlice(dataprovider.PermListItems, val) {
|
|
t.Error("expected permission list not found")
|
|
}
|
|
if len(val) != 1 {
|
|
t.Errorf("Unexpected number of permissions, expected 1, actual: %v", len(val))
|
|
}
|
|
} else {
|
|
t.Errorf("expected dir not found in permissions")
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestUpdateUserInvalidJsonMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer([]byte("Invalid json")))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestUpdateUserInvalidParamsMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
user.HomeDir = ""
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
userID := user.ID
|
|
user.ID = 0
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(userID, 10), bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
user.ID = userID
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/0", bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodPut, userPath+"/a", bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestGetUsersMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=510&offset=0&order=ASC&username="+defaultUsername, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var users []dataprovider.User
|
|
err = render.DecodeJSON(rr.Body, &users)
|
|
if err != nil {
|
|
t.Errorf("Error decoding users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=a&offset=0&order=ASC", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=a&order=ASC", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASCa", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestDeleteUserInvalidParamsMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodDelete, userPath+"/0", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/a", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestGetQuotaScansMock(t *testing.T) {
|
|
req, err := http.NewRequest("GET", quotaScanPath, nil)
|
|
if err != nil {
|
|
t.Errorf("error get quota scan: %v", err)
|
|
}
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestStartQuotaScanMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
_, err = os.Stat(user.HomeDir)
|
|
if err == nil {
|
|
os.Remove(user.HomeDir)
|
|
}
|
|
// simulate a duplicate quota scan
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
sftpd.AddQuotaScan(user.Username)
|
|
req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusConflict, rr.Code)
|
|
sftpd.RemoveQuotaScan(user.Username)
|
|
|
|
userAsJSON = getUserAsJSON(t, user)
|
|
req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusCreated, rr.Code)
|
|
|
|
req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var scans []sftpd.ActiveQuotaScan
|
|
err = render.DecodeJSON(rr.Body, &scans)
|
|
if err != nil {
|
|
t.Errorf("Error get active scans: %v", err)
|
|
}
|
|
for len(scans) > 0 {
|
|
req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = render.DecodeJSON(rr.Body, &scans)
|
|
if err != nil {
|
|
t.Errorf("Error get active scans: %v", err)
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
_, err = os.Stat(user.HomeDir)
|
|
if err != nil && os.IsNotExist(err) {
|
|
os.MkdirAll(user.HomeDir, 0777)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusCreated, rr.Code)
|
|
|
|
req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = render.DecodeJSON(rr.Body, &scans)
|
|
if err != nil {
|
|
t.Errorf("Error get active scans: %v", err)
|
|
}
|
|
for len(scans) > 0 {
|
|
req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = render.DecodeJSON(rr.Body, &scans)
|
|
if err != nil {
|
|
t.Errorf("Error get active scans: %v", err)
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
os.RemoveAll(user.GetHomeDir())
|
|
}
|
|
|
|
func TestStartQuotaScanBadUserMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
}
|
|
|
|
func TestStartQuotaScanNonExistentUserMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer([]byte("invalid json")))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
}
|
|
|
|
func TestGetVersionMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, versionPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestGetConnectionsMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, activeConnectionsPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestDeleteActiveConnectionMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodDelete, activeConnectionsPath+"/connectionID", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
}
|
|
|
|
func TestNotFoundMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, "/non/existing/path", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
}
|
|
|
|
func TestMethodNotAllowedMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodPost, activeConnectionsPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusMethodNotAllowed, rr.Code)
|
|
}
|
|
|
|
func TestMetricsMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, metricsPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestGetWebRootMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, "/", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusMovedPermanently, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webBasePath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusMovedPermanently, rr.Code)
|
|
}
|
|
|
|
func TestBasicWebUsersMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
user1 := getTestUser()
|
|
user1.Username += "1"
|
|
user1AsJSON := getUserAsJSON(t, user1)
|
|
req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(user1AsJSON))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = render.DecodeJSON(rr.Body, &user1)
|
|
if err != nil {
|
|
t.Errorf("Error get user1: %v", err)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=a", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=1", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUserPath, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUserPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUserPath+"/a", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
form := make(url.Values)
|
|
form.Set("username", user.Username)
|
|
b, contentType, _ := getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusNotFound, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/a", &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusBadRequest, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user1.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestWebUserAddMock(t *testing.T) {
|
|
user := getTestUser()
|
|
user.UploadBandwidth = 32
|
|
user.DownloadBandwidth = 64
|
|
user.UID = 1000
|
|
mappedDir := filepath.Join(os.TempDir(), "mapped")
|
|
form := make(url.Values)
|
|
form.Set("username", user.Username)
|
|
form.Set("home_dir", user.HomeDir)
|
|
form.Set("password", user.Password)
|
|
form.Set("status", strconv.Itoa(user.Status))
|
|
form.Set("expiration_date", "")
|
|
form.Set("permissions", "*")
|
|
form.Set("sub_dirs_permissions", " /subdir::list ,download ")
|
|
form.Set("virtual_folders", fmt.Sprintf(" /vdir:: %v ", mappedDir))
|
|
form.Set("allowed_extensions", "/dir1::.jpg,.png")
|
|
form.Set("denied_extensions", "/dir1::.zip")
|
|
b, contentType, _ := getMultipartFormData(form, "", "")
|
|
// test invalid url escape
|
|
req, _ := http.NewRequest(http.MethodPost, webUserPath+"?a=%2", &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("public_keys", testPubKey)
|
|
form.Set("uid", strconv.FormatInt(int64(user.UID), 10))
|
|
form.Set("gid", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid gid
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("gid", "0")
|
|
form.Set("max_sessions", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid max sessions
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("max_sessions", "0")
|
|
form.Set("quota_size", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid quota size
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("quota_size", "0")
|
|
form.Set("quota_files", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid quota files
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("quota_files", "0")
|
|
form.Set("upload_bandwidth", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid upload bandwidth
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("upload_bandwidth", strconv.FormatInt(user.UploadBandwidth, 10))
|
|
form.Set("download_bandwidth", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid download bandwidth
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("download_bandwidth", strconv.FormatInt(user.DownloadBandwidth, 10))
|
|
form.Set("status", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid status
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("status", strconv.Itoa(user.Status))
|
|
form.Set("expiration_date", "123")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid expiration date
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("expiration_date", "")
|
|
form.Set("allowed_ip", "invalid,ip")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid allowed_ip
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("allowed_ip", "")
|
|
form.Set("denied_ip", "192.168.1.2") // it should be 192.168.1.2/32
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
// test invalid denied_ip
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
form.Set("denied_ip", "")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusSeeOther, rr.Code)
|
|
// the user already exists, was created with the above request
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var users []dataprovider.User
|
|
err := render.DecodeJSON(rr.Body, &users)
|
|
if err != nil {
|
|
t.Errorf("Error decoding users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected, actual: %v", len(users))
|
|
}
|
|
newUser := users[0]
|
|
if newUser.UID != user.UID {
|
|
t.Errorf("uid does not match")
|
|
}
|
|
if newUser.UploadBandwidth != user.UploadBandwidth {
|
|
t.Errorf("upload_bandwidth does not match")
|
|
}
|
|
if newUser.DownloadBandwidth != user.DownloadBandwidth {
|
|
t.Errorf("download_bandwidth does not match")
|
|
}
|
|
if !utils.IsStringInSlice(testPubKey, newUser.PublicKeys) {
|
|
t.Errorf("public_keys does not match")
|
|
}
|
|
if val, ok := newUser.Permissions["/subdir"]; ok {
|
|
if !utils.IsStringInSlice(dataprovider.PermListItems, val) || !utils.IsStringInSlice(dataprovider.PermDownload, val) {
|
|
t.Error("permssions for /subdir does not match")
|
|
}
|
|
} else {
|
|
t.Errorf("user permissions must contain /somedir, actual: %v", newUser.Permissions)
|
|
}
|
|
vfolderFoumd := false
|
|
for _, v := range newUser.VirtualFolders {
|
|
if v.VirtualPath == "/vdir" && v.MappedPath == mappedDir {
|
|
vfolderFoumd = true
|
|
}
|
|
}
|
|
if !vfolderFoumd {
|
|
t.Errorf("virtual folders must contain /vdir, actual: %+v", newUser.VirtualFolders)
|
|
}
|
|
extFilters := newUser.Filters.FileExtensions[0]
|
|
if !utils.IsStringInSlice(".zip", extFilters.DeniedExtensions) {
|
|
t.Errorf("unexpected denied extensions: %v", extFilters.DeniedExtensions)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(newUser.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestWebUserUpdateMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
user.MaxSessions = 1
|
|
user.QuotaFiles = 2
|
|
user.QuotaSize = 3
|
|
user.GID = 1000
|
|
form := make(url.Values)
|
|
form.Set("username", user.Username)
|
|
form.Set("home_dir", user.HomeDir)
|
|
form.Set("uid", "0")
|
|
form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
|
|
form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
|
|
form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
|
|
form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
|
|
form.Set("upload_bandwidth", "0")
|
|
form.Set("download_bandwidth", "0")
|
|
form.Set("permissions", "*")
|
|
form.Set("sub_dirs_permissions", "/otherdir :: list ,upload ")
|
|
form.Set("status", strconv.Itoa(user.Status))
|
|
form.Set("expiration_date", "2020-01-01 00:00:00")
|
|
form.Set("allowed_ip", " 192.168.1.3/32, 192.168.2.0/24 ")
|
|
form.Set("denied_ip", " 10.0.0.2/32 ")
|
|
form.Set("denied_extensions", "/dir1::.zip")
|
|
form.Set("ssh_login_methods", dataprovider.SSHLoginMethodKeyboardInteractive)
|
|
b, contentType, _ := getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusSeeOther, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var users []dataprovider.User
|
|
render.DecodeJSON(rr.Body, &users)
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
updateUser := users[0]
|
|
if user.HomeDir != updateUser.HomeDir {
|
|
t.Errorf("home dir does not match")
|
|
}
|
|
if user.MaxSessions != updateUser.MaxSessions {
|
|
t.Errorf("max_sessions does not match")
|
|
}
|
|
if user.QuotaFiles != updateUser.QuotaFiles {
|
|
t.Errorf("quota_files does not match")
|
|
}
|
|
if user.QuotaSize != updateUser.QuotaSize {
|
|
t.Errorf("quota_size does not match")
|
|
}
|
|
if user.GID != updateUser.GID {
|
|
t.Errorf("gid does not match")
|
|
}
|
|
if val, ok := updateUser.Permissions["/otherdir"]; ok {
|
|
if !utils.IsStringInSlice(dataprovider.PermListItems, val) || !utils.IsStringInSlice(dataprovider.PermUpload, val) {
|
|
t.Error("permssions for /otherdir does not match")
|
|
}
|
|
} else {
|
|
t.Errorf("user permissions must contains /otherdir, actual: %v", updateUser.Permissions)
|
|
}
|
|
if !utils.IsStringInSlice("192.168.1.3/32", updateUser.Filters.AllowedIP) {
|
|
t.Errorf("Allowed IP/Mask does not match: %v", updateUser.Filters.AllowedIP)
|
|
}
|
|
if !utils.IsStringInSlice("10.0.0.2/32", updateUser.Filters.DeniedIP) {
|
|
t.Errorf("Denied IP/Mask does not match: %v", updateUser.Filters.DeniedIP)
|
|
}
|
|
if !utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods) {
|
|
t.Errorf("Denied login methods does not match: %v", updateUser.Filters.DeniedLoginMethods)
|
|
}
|
|
if !utils.IsStringInSlice(".zip", updateUser.Filters.FileExtensions[0].DeniedExtensions) {
|
|
t.Errorf("unexpected extensions filter: %+v", updateUser.Filters.FileExtensions)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestWebUserS3Mock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 1
|
|
user.FsConfig.S3Config.Bucket = "test"
|
|
user.FsConfig.S3Config.Region = "eu-west-1"
|
|
user.FsConfig.S3Config.AccessKey = "access-key"
|
|
user.FsConfig.S3Config.AccessSecret = "access-secret"
|
|
user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
|
|
user.FsConfig.S3Config.StorageClass = "Standard"
|
|
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/"
|
|
user.FsConfig.S3Config.UploadPartSize = 5
|
|
user.FsConfig.S3Config.UploadConcurrency = 4
|
|
form := make(url.Values)
|
|
form.Set("username", user.Username)
|
|
form.Set("home_dir", user.HomeDir)
|
|
form.Set("uid", "0")
|
|
form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
|
|
form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
|
|
form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
|
|
form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
|
|
form.Set("upload_bandwidth", "0")
|
|
form.Set("download_bandwidth", "0")
|
|
form.Set("permissions", "*")
|
|
form.Set("sub_dirs_permissions", "")
|
|
form.Set("status", strconv.Itoa(user.Status))
|
|
form.Set("expiration_date", "2020-01-01 00:00:00")
|
|
form.Set("allowed_ip", "")
|
|
form.Set("denied_ip", "")
|
|
form.Set("fs_provider", "1")
|
|
form.Set("s3_bucket", user.FsConfig.S3Config.Bucket)
|
|
form.Set("s3_region", user.FsConfig.S3Config.Region)
|
|
form.Set("s3_access_key", user.FsConfig.S3Config.AccessKey)
|
|
form.Set("s3_access_secret", user.FsConfig.S3Config.AccessSecret)
|
|
form.Set("s3_storage_class", user.FsConfig.S3Config.StorageClass)
|
|
form.Set("s3_endpoint", user.FsConfig.S3Config.Endpoint)
|
|
form.Set("s3_key_prefix", user.FsConfig.S3Config.KeyPrefix)
|
|
form.Set("allowed_extensions", "/dir1::.jpg,.png")
|
|
form.Set("denied_extensions", "/dir2::.zip")
|
|
// test invalid s3_upload_part_size
|
|
form.Set("s3_upload_part_size", "a")
|
|
b, contentType, _ := getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
// test invalid s3_concurrency
|
|
form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10))
|
|
form.Set("s3_upload_concurrency", "a")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
// now add the user
|
|
form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency))
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusSeeOther, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var users []dataprovider.User
|
|
err = render.DecodeJSON(rr.Body, &users)
|
|
if err != nil {
|
|
t.Errorf("Error decoding users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
updateUser := users[0]
|
|
if updateUser.ExpirationDate != 1577836800000 {
|
|
t.Errorf("invalid expiration date: %v", updateUser.ExpirationDate)
|
|
}
|
|
if updateUser.FsConfig.S3Config.Bucket != user.FsConfig.S3Config.Bucket {
|
|
t.Error("s3 bucket mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.Region != user.FsConfig.S3Config.Region {
|
|
t.Error("s3 region mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.AccessKey != user.FsConfig.S3Config.AccessKey {
|
|
t.Error("s3 access key mismatch")
|
|
}
|
|
if !strings.HasPrefix(updateUser.FsConfig.S3Config.AccessSecret, "$aes$") {
|
|
t.Error("s3 access secret is not encrypted")
|
|
}
|
|
if updateUser.FsConfig.S3Config.StorageClass != user.FsConfig.S3Config.StorageClass {
|
|
t.Error("s3 storage class mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.Endpoint != user.FsConfig.S3Config.Endpoint {
|
|
t.Error("s3 endpoint mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.KeyPrefix != user.FsConfig.S3Config.KeyPrefix {
|
|
t.Error("s3 key prefix mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.UploadPartSize != user.FsConfig.S3Config.UploadPartSize {
|
|
t.Error("s3 upload part size mismatch")
|
|
}
|
|
if updateUser.FsConfig.S3Config.UploadConcurrency != user.FsConfig.S3Config.UploadConcurrency {
|
|
t.Error("s3 upload concurrency mismatch")
|
|
}
|
|
if len(updateUser.Filters.FileExtensions) != 2 {
|
|
t.Errorf("unexpected extensions filter: %+v", updateUser.Filters.FileExtensions)
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestWebUserGCSMock(t *testing.T) {
|
|
user := getTestUser()
|
|
userAsJSON := getUserAsJSON(t, user)
|
|
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err := render.DecodeJSON(rr.Body, &user)
|
|
if err != nil {
|
|
t.Errorf("Error get user: %v", err)
|
|
}
|
|
credentialsFilePath := filepath.Join(os.TempDir(), "gcs.json")
|
|
err = createTestFile(credentialsFilePath, 0)
|
|
if err != nil {
|
|
t.Errorf("unable to create credential test file: %v", err)
|
|
}
|
|
user.FsConfig.Provider = 2
|
|
user.FsConfig.GCSConfig.Bucket = "test"
|
|
user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
|
|
user.FsConfig.GCSConfig.StorageClass = "standard"
|
|
form := make(url.Values)
|
|
form.Set("username", user.Username)
|
|
form.Set("home_dir", user.HomeDir)
|
|
form.Set("uid", "0")
|
|
form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
|
|
form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
|
|
form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
|
|
form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
|
|
form.Set("upload_bandwidth", "0")
|
|
form.Set("download_bandwidth", "0")
|
|
form.Set("permissions", "*")
|
|
form.Set("sub_dirs_permissions", "")
|
|
form.Set("status", strconv.Itoa(user.Status))
|
|
form.Set("expiration_date", "2020-01-01 00:00:00")
|
|
form.Set("allowed_ip", "")
|
|
form.Set("denied_ip", "")
|
|
form.Set("fs_provider", "2")
|
|
form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket)
|
|
form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass)
|
|
form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix)
|
|
form.Set("allowed_extensions", "/dir1::.jpg,.png")
|
|
b, contentType, _ := getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = createTestFile(credentialsFilePath, 4096)
|
|
if err != nil {
|
|
t.Errorf("unable to create credential test file: %v", err)
|
|
}
|
|
b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusSeeOther, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
var users []dataprovider.User
|
|
render.DecodeJSON(rr.Body, &users)
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
updateUser := users[0]
|
|
if updateUser.ExpirationDate != 1577836800000 {
|
|
t.Errorf("invalid expiration date: %v", updateUser.ExpirationDate)
|
|
}
|
|
if updateUser.FsConfig.Provider != user.FsConfig.Provider {
|
|
t.Error("fs provider mismatch")
|
|
}
|
|
if updateUser.FsConfig.GCSConfig.Bucket != user.FsConfig.GCSConfig.Bucket {
|
|
t.Error("GCS bucket mismatch")
|
|
}
|
|
if updateUser.FsConfig.GCSConfig.StorageClass != user.FsConfig.GCSConfig.StorageClass {
|
|
t.Error("GCS storage class mismatch")
|
|
}
|
|
if updateUser.FsConfig.GCSConfig.KeyPrefix != user.FsConfig.GCSConfig.KeyPrefix {
|
|
t.Error("GCS key prefix mismatch")
|
|
}
|
|
if updateUser.Filters.FileExtensions[0].Path != "/dir1" {
|
|
t.Errorf("unexpected extensions filter: %+v", updateUser.Filters.FileExtensions)
|
|
}
|
|
form.Set("gcs_auto_credentials", "on")
|
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
|
|
req.Header.Set("Content-Type", contentType)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusSeeOther, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
err = render.DecodeJSON(rr.Body, &users)
|
|
if err != nil {
|
|
t.Errorf("Error decoding users: %v", err)
|
|
}
|
|
if len(users) != 1 {
|
|
t.Errorf("1 user is expected")
|
|
}
|
|
updateUser = users[0]
|
|
if updateUser.FsConfig.GCSConfig.AutomaticCredentials != 1 {
|
|
t.Error("GCS automatic credentials mismatch")
|
|
}
|
|
req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
os.Remove(credentialsFilePath)
|
|
}
|
|
|
|
func TestProviderClosedMock(t *testing.T) {
|
|
if providerDriverName == dataprovider.BoltDataProviderName {
|
|
t.Skip("skipping test provider errors for bolt provider")
|
|
}
|
|
dataProvider := dataprovider.GetProvider()
|
|
dataprovider.Close(dataProvider)
|
|
req, _ := http.NewRequest(http.MethodGet, webUsersPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
|
|
req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
|
|
form := make(url.Values)
|
|
form.Set("username", "test")
|
|
req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode()))
|
|
rr = executeRequest(req)
|
|
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
|
|
config.LoadConfig(configDir, "")
|
|
providerConf := config.GetProviderConf()
|
|
providerConf.CredentialsPath = credentialsPath
|
|
os.RemoveAll(credentialsPath)
|
|
err := dataprovider.Initialize(providerConf, configDir)
|
|
if err != nil {
|
|
t.Errorf("error initializing data provider")
|
|
}
|
|
httpd.SetDataProvider(dataprovider.GetProvider())
|
|
sftpd.SetDataProvider(dataprovider.GetProvider())
|
|
}
|
|
|
|
func TestGetWebConnectionsMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, webConnectionsPath, nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestStaticFilesMock(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, "/static/favicon.ico", nil)
|
|
rr := executeRequest(req)
|
|
checkResponseCode(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func waitTCPListening(address string) {
|
|
for {
|
|
conn, err := net.Dial("tcp", address)
|
|
if err != nil {
|
|
logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
|
|
time.Sleep(100 * time.Millisecond)
|
|
continue
|
|
}
|
|
logger.InfoToConsole("tcp server %v now listening\n", address)
|
|
defer conn.Close()
|
|
break
|
|
}
|
|
}
|
|
|
|
func getTestUser() dataprovider.User {
|
|
user := dataprovider.User{
|
|
Username: defaultUsername,
|
|
Password: defaultPassword,
|
|
HomeDir: filepath.Join(homeBasePath, defaultUsername),
|
|
Status: 1,
|
|
}
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = defaultPerms
|
|
return user
|
|
}
|
|
|
|
func getUserAsJSON(t *testing.T, user dataprovider.User) []byte {
|
|
json, err := json.Marshal(user)
|
|
if err != nil {
|
|
t.Errorf("error get user as json: %v", err)
|
|
return []byte("{}")
|
|
}
|
|
return json
|
|
}
|
|
|
|
func executeRequest(req *http.Request) *httptest.ResponseRecorder {
|
|
rr := httptest.NewRecorder()
|
|
testServer.Config.Handler.ServeHTTP(rr, req)
|
|
return rr
|
|
}
|
|
|
|
func checkResponseCode(t *testing.T, expected, actual int) {
|
|
if expected != actual {
|
|
t.Errorf("Expected response code %d. Got %d", expected, actual)
|
|
}
|
|
}
|
|
|
|
func createTestFile(path string, size int64) error {
|
|
baseDir := filepath.Dir(path)
|
|
if _, err := os.Stat(baseDir); os.IsNotExist(err) {
|
|
os.MkdirAll(baseDir, 0777)
|
|
}
|
|
content := make([]byte, size)
|
|
if size > 0 {
|
|
_, err := rand.Read(content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return ioutil.WriteFile(path, content, 0666)
|
|
}
|
|
|
|
func getMultipartFormData(values url.Values, fileFieldName, filePath string) (bytes.Buffer, string, error) {
|
|
var b bytes.Buffer
|
|
w := multipart.NewWriter(&b)
|
|
for k, v := range values {
|
|
for _, s := range v {
|
|
if err := w.WriteField(k, s); err != nil {
|
|
return b, "", err
|
|
}
|
|
}
|
|
}
|
|
if len(fileFieldName) > 0 && len(filePath) > 0 {
|
|
fw, err := w.CreateFormFile(fileFieldName, filepath.Base(filePath))
|
|
if err != nil {
|
|
return b, "", err
|
|
}
|
|
f, err := os.Open(filePath)
|
|
if err != nil {
|
|
return b, "", err
|
|
}
|
|
if _, err = io.Copy(fw, f); err != nil {
|
|
return b, "", err
|
|
}
|
|
}
|
|
err := w.Close()
|
|
return b, w.FormDataContentType(), err
|
|
}
|