refactor: parameterize XFTP store with FSType singleton dispatch

This commit is contained in:
shum
2026-04-14 13:30:33 +00:00
parent 7aabf24eb0
commit 2baa868bc0
9 changed files with 218 additions and 165 deletions

View File

@@ -238,7 +238,7 @@ xftpServer cfg@XFTPServerConfig {xftpPort, transportConfig, inactiveClientExpira
stopServer :: M s ()
stopServer = do
st <- asks store
st <- asks fileStore
liftIO $ closeFileStore st
saveServerStats
logNote "Server stopped"
@@ -366,13 +366,13 @@ xftpServer cfg@XFTPServerConfig {xftpPort, transportConfig, inactiveClientExpira
XFTPServerConfig {controlPortUserAuth = user, controlPortAdminAuth = admin} = cfg
CPStatsRTS -> E.tryAny getRTSStats >>= either (hPrint h) (hPrint h)
CPDelete fileId -> withUserRole $ unliftIO u $ do
fs <- asks store
fs <- asks fileStore
r <- runExceptT $ do
(fr, _) <- ExceptT $ liftIO $ getFile fs SFRecipient fileId
ExceptT $ deleteServerFile_ fr
liftIO . hPutStrLn h $ either (\e -> "error: " <> show e) (\() -> "ok") r
CPBlock fileId info -> withUserRole $ unliftIO u $ do
fs <- asks store
fs <- asks fileStore
r <- runExceptT $ do
(fr, _) <- ExceptT $ liftIO $ getFile fs SFRecipient fileId
ExceptT $ blockServerFile fr info
@@ -449,7 +449,7 @@ verifyXFTPTransmission thAuth (tAuth, authorized, (corrId, fId, cmd)) =
where
verifyCmd :: SFileParty p -> M s VerificationResult
verifyCmd party = do
st <- asks store
st <- asks fileStore
liftIO $ verify =<< getFile st party fId
where
verify = \case
@@ -485,7 +485,7 @@ processXFTPRequest HTTP2Body {bodyPart} = \case
noFile resp = pure (resp, Nothing)
createFile :: FileInfo -> NonEmpty RcvPublicAuthKey -> M s FileResponse
createFile file rks = do
st <- asks store
st <- asks fileStore
r <- runExceptT $ do
sizes <- asks $ allowedChunkSizes . config
unless (size file `elem` sizes) $ throwE SIZE
@@ -522,7 +522,7 @@ processXFTPRequest HTTP2Body {bodyPart} = \case
r -> pure r
addRecipients :: XFTPFileId -> NonEmpty RcvPublicAuthKey -> M s FileResponse
addRecipients sId rks = do
st <- asks store
st <- asks fileStore
r <- runExceptT $ do
rcps <- mapM (ExceptT . addRecipientRetry st 3 sId) rks
lift $ withFileLog $ \sl -> logAddRecipients sl sId rcps
@@ -559,7 +559,7 @@ processXFTPRequest HTTP2Body {bodyPart} = \case
receiveChunk (XFTPRcvChunkSpec fPath size digest) >>= \case
Right () -> do
stats <- asks serverStats
st <- asks store
st <- asks fileStore
liftIO (setFilePath st senderId fPath) >>= \case
Right () -> do
withFileLog $ \sl -> logPutFile sl senderId fPath
@@ -608,7 +608,7 @@ processXFTPRequest HTTP2Body {bodyPart} = \case
ackFileReception :: RecipientId -> FileRec -> M s FileResponse
ackFileReception rId fr = do
withFileLog (`logAckFile` rId)
st <- asks store
st <- asks fileStore
liftIO $ deleteRecipient st rId fr
incFileStat fileDownloadAcks
pure FROk
@@ -629,7 +629,7 @@ deleteOrBlockServerFile_ FileRec {filePath, fileInfo} stat storeAction = runExce
path <- readTVarIO filePath
stats <- asks serverStats
ExceptT $ first (\(_ :: SomeException) -> FILE_IO) <$> try (forM_ path $ \p -> whenM (doesFileExist p) (removeFile p >> deletedStats stats))
st <- asks store
st <- asks fileStore
ExceptT $ liftIO $ storeAction st
forM_ path $ \_ -> do
us <- asks usedStorage
@@ -645,7 +645,7 @@ getFileTime = getRoundedSystemTime
expireServerFiles :: FileStoreClass s => Maybe Int -> ExpirationConfig -> M s ()
expireServerFiles itemDelay expCfg = do
st <- asks store
st <- asks fileStore
us <- asks usedStorage
usedStart <- readTVarIO us
old <- liftIO $ expireBeforeEpoch expCfg
@@ -704,7 +704,7 @@ restoreServerStats = asks (serverStatsBackupFile . config) >>= mapM_ restoreStat
liftIO (strDecode <$> B.readFile f) >>= \case
Right d@FileServerStatsData {_filesCount = statsFilesCount, _filesSize = statsFilesSize} -> do
s <- asks serverStats
st <- asks store
st <- asks fileStore
_filesCount <- liftIO $ getFileCount st
_filesSize <- readTVarIO =<< asks usedStorage
liftIO $ setFileServerStats s d {_filesCount, _filesSize}

View File

@@ -1,6 +1,7 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
@@ -8,16 +9,23 @@
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TypeFamilies #-}
module Simplex.FileTransfer.Server.Env
( XFTPServerConfig (..),
XFTPStoreConfig (..),
XFTPEnv (..),
XFTPRequest (..),
XFTPStoreType,
FileStore (..),
AFStoreType (..),
fileStore,
fromFileStore,
defaultInactiveClientExpiration,
defFileExpirationHours,
defaultFileExpiration,
newXFTPServerEnv,
readFileStoreType,
runWithStoreConfig,
checkFileStoreMode,
importToDatabase,
@@ -111,9 +119,31 @@ data XFTPStoreConfig s where
XSCDatabase :: PostgresFileStoreCfg -> XFTPStoreConfig PostgresFileStore
#endif
type family XFTPStoreType (fs :: FSType) where
XFTPStoreType 'FSMemory = STMFileStore
#if defined(dbServerPostgres)
XFTPStoreType 'FSPostgres = PostgresFileStore
#endif
data FileStore s where
StoreMemory :: STMFileStore -> FileStore STMFileStore
#if defined(dbServerPostgres)
StoreDatabase :: PostgresFileStore -> FileStore PostgresFileStore
#endif
data AFStoreType = forall fs. FileStoreClass (XFTPStoreType fs) => AFSType (SFSType fs)
fromFileStore :: FileStore s -> s
fromFileStore = \case
StoreMemory s -> s
#if defined(dbServerPostgres)
StoreDatabase s -> s
#endif
{-# INLINE fromFileStore #-}
data XFTPEnv s = XFTPEnv
{ config :: XFTPServerConfig s,
store :: s,
fileStore_ :: FileStore s,
usedStorage :: TVar Int64,
storeLog :: Maybe (StoreLog 'WriteMode),
random :: TVar ChaChaDRG,
@@ -123,6 +153,10 @@ data XFTPEnv s = XFTPEnv
serverStats :: FileServerStats
}
fileStore :: XFTPEnv s -> s
fileStore = fromFileStore . fileStore_
{-# INLINE fileStore #-}
defFileExpirationHours :: Int64
defFileExpirationHours = 48
@@ -136,18 +170,18 @@ defaultFileExpiration =
newXFTPServerEnv :: FileStoreClass s => XFTPServerConfig s -> IO (XFTPEnv s)
newXFTPServerEnv config@XFTPServerConfig {serverStoreCfg, fileSizeQuota, xftpCredentials, httpCredentials} = do
random <- C.newRandom
(store, storeLog) <- case serverStoreCfg of
(fileStore_, storeLog) <- case serverStoreCfg of
XSCMemory storeLogPath -> do
st <- newFileStore ()
sl <- mapM (`readWriteFileStore` st) storeLogPath
atomically $ writeTVar (stmStoreLog st) sl
pure (st, sl)
pure (StoreMemory st, sl)
#if defined(dbServerPostgres)
XSCDatabase dbCfg -> do
st <- newFileStore dbCfg
pure (st, Nothing)
pure (StoreDatabase st, Nothing)
#endif
used <- getUsedStorage store
used <- getUsedStorage (fromFileStore fileStore_)
usedStorage <- newTVarIO used
forM_ fileSizeQuota $ \quota -> do
logNote $ "Total / available storage: " <> tshow quota <> " / " <> tshow (quota - used)
@@ -156,35 +190,45 @@ newXFTPServerEnv config@XFTPServerConfig {serverStoreCfg, fileSizeQuota, xftpCre
httpServerCreds <- mapM loadServerCredential httpCredentials
Fingerprint fp <- loadFingerprint xftpCredentials
serverStats <- newFileServerStats =<< getCurrentTime
pure XFTPEnv {config, store, usedStorage, storeLog, random, tlsServerCreds, httpServerCreds, serverIdentity = C.KeyHash fp, serverStats}
pure XFTPEnv {config, fileStore_, usedStorage, storeLog, random, tlsServerCreds, httpServerCreds, serverIdentity = C.KeyHash fp, serverStats}
data XFTPRequest
= XFTPReqNew FileInfo (NonEmpty RcvPublicAuthKey) (Maybe BasicAuth)
| XFTPReqCmd XFTPFileId FileRec FileCmd
| XFTPReqPing
-- | Select and run the store config based on INI settings.
readFileStoreType :: String -> Either String AFStoreType
readFileStoreType = \case
"memory" -> Right $ AFSType SFSMemory
#if defined(dbServerPostgres)
"database" -> Right $ AFSType SFSPostgres
#else
"database" -> Left "Error: server binary is compiled without support for PostgreSQL database.\nPlease re-compile with `cabal build -fserver_postgres`."
#endif
other -> Left $ "Invalid store_files value: " <> other
-- | Dispatch store config from AFStoreType singleton and run the callback.
-- CPP guards for Postgres are handled here so Main.hs stays CPP-free.
runWithStoreConfig ::
AFStoreType ->
Ini ->
String ->
Maybe FilePath ->
FilePath ->
MigrationConfirmation ->
(forall s. FileStoreClass s => XFTPStoreConfig s -> IO ()) ->
IO ()
runWithStoreConfig _ini storeType storeLogFile_ _storeLogFilePath _confirmMigrations run = case storeType of
"memory" -> run $ XSCMemory storeLogFile_
runWithStoreConfig (AFSType fs) ini storeLogFilePath confirmMigrations run =
run $ iniStoreCfg fs
where
enableStoreLog' = settingIsOn "STORE_LOG" "enable" ini
iniStoreCfg :: SFSType fs -> XFTPStoreConfig (XFTPStoreType fs)
iniStoreCfg SFSMemory = XSCMemory (enableStoreLog' $> storeLogFilePath)
#if defined(dbServerPostgres)
"database" -> run $ XSCDatabase dbCfg
where
enableDbStoreLog' = settingIsOn "STORE_LOG" "db_store_log" _ini
dbStoreLogPath = enableDbStoreLog' $> _storeLogFilePath
dbCfg = PostgresFileStoreCfg {dbOpts = iniDBOptions _ini defaultXFTPDBOpts, dbStoreLogPath, confirmMigrations = _confirmMigrations}
#else
"database" -> error "Error: server binary is compiled without support for PostgreSQL database.\nPlease re-compile with `cabal build -fserver_postgres`."
iniStoreCfg SFSPostgres = XSCDatabase dbCfg
where
enableDbStoreLog' = settingIsOn "STORE_LOG" "db_store_log" ini
dbStoreLogPath = enableDbStoreLog' $> storeLogFilePath
dbCfg = PostgresFileStoreCfg {dbOpts = iniDBOptions ini defaultXFTPDBOpts, dbStoreLogPath, confirmMigrations}
#endif
_ -> error $ "Invalid store_files value: " <> storeType
-- | Validate startup config when store_files=database.
checkFileStoreMode :: Ini -> String -> FilePath -> IO ()

View File

@@ -29,7 +29,7 @@ import Options.Applicative
import Simplex.FileTransfer.Chunks
import Simplex.FileTransfer.Description (FileSize (..))
import Simplex.FileTransfer.Server (runXFTPServer)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), XFTPStoreConfig, defFileExpirationHours, defaultFileExpiration, defaultInactiveClientExpiration, runWithStoreConfig, checkFileStoreMode, importToDatabase, exportFromDatabase)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), XFTPStoreConfig, AFStoreType (..), defFileExpirationHours, defaultFileExpiration, defaultInactiveClientExpiration, readFileStoreType, runWithStoreConfig, checkFileStoreMode, importToDatabase, exportFromDatabase)
import Simplex.FileTransfer.Transport (alpnSupportedXFTPhandshakes, supportedFileServerVRange)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Encoding.String
@@ -214,20 +214,22 @@ xftpServerCLI_ generateSite serveStaticFiles cfgPath logPath = do
printSourceCode (sourceCode <$> information)
let storeType = fromRight "memory" $ T.unpack <$> lookupValue "STORE_LOG" "store_files" ini
checkFileStoreMode ini storeType storeLogFilePath
runWithStoreConfig ini storeType (enableStoreLog $> storeLogFilePath) storeLogFilePath confirmMigrations $ \storeCfg -> do
let cfg = serverConfig storeCfg
printXFTPConfig cfg
case webStaticPath' of
Just path -> do
let onionHost =
either (const Nothing) (find isOnion) $
strDecode @(L.NonEmpty TransportHost) . encodeUtf8 =<< lookupValue "TRANSPORT" "host" ini
webHttpPort = eitherToMaybe (lookupValue "WEB" "http" ini) >>= readMaybe . T.unpack
generateSite cfg information onionHost path
when (isJust webHttpPort || isJust webHttpsParams') $
serveStaticFiles EmbeddedWebParams {webStaticPath = path, webHttpPort, webHttpsParams = webHttpsParams'}
Nothing -> pure ()
runXFTPServer cfg
case readFileStoreType storeType of
Left err -> error err
Right fsType -> runWithStoreConfig fsType ini storeLogFilePath confirmMigrations $ \storeCfg -> do
let cfg = serverConfig storeCfg
printXFTPConfig cfg
case webStaticPath' of
Just path -> do
let onionHost =
either (const Nothing) (find isOnion) $
strDecode @(L.NonEmpty TransportHost) . encodeUtf8 =<< lookupValue "TRANSPORT" "host" ini
webHttpPort = eitherToMaybe (lookupValue "WEB" "http" ini) >>= readMaybe . T.unpack
generateSite cfg information onionHost path
when (isJust webHttpPort || isJust webHttpsParams') $
serveStaticFiles EmbeddedWebParams {webStaticPath = path, webHttpPort, webHttpsParams = webHttpsParams'}
Nothing -> pure ()
runXFTPServer cfg
where
isOnion = \case THOnionHost _ -> True; _ -> False
enableStoreLog = settingIsOn "STORE_LOG" "enable" ini

View File

@@ -1,5 +1,6 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
@@ -7,7 +8,9 @@
{-# LANGUAGE TypeFamilies #-}
module Simplex.FileTransfer.Server.Store
( FileStoreClass (..),
( FSType (..),
SFSType (..),
FileStoreClass (..),
FileRec (..),
FileRecipient (..),
STMFileStore (..),
@@ -16,6 +19,8 @@ module Simplex.FileTransfer.Server.Store
)
where
import Data.Kind (Type)
import Control.Concurrent.STM
import Control.Monad (forM, void)
import qualified Data.Attoparsec.ByteString.Char8 as A
@@ -38,6 +43,12 @@ import Simplex.Messaging.TMap (TMap)
import qualified Simplex.Messaging.TMap as TM
import Simplex.Messaging.Util (ifM)
data FSType = FSMemory | FSPostgres
data SFSType :: FSType -> Type where
SFSMemory :: SFSType 'FSMemory
SFSPostgres :: SFSType 'FSPostgres
data FileRec = FileRec
{ senderId :: SenderId,
fileInfo :: FileInfo,

View File

@@ -34,7 +34,8 @@ import Test.Hspec hiding (fit, it)
import Util
import XFTPAgent
import XFTPCLI (xftpCLIFileTests)
import XFTPClient (xftpMemoryServer, xftpMemoryServer2)
import Simplex.FileTransfer.Server.Env (AFStoreType (..))
import Simplex.FileTransfer.Server.Store (SFSType (..))
import XFTPServerTests (xftpServerTests)
import WebTests (webTests)
import XFTPWebTests (xftpWebTests)
@@ -54,7 +55,7 @@ import PostgresSchemaDump (postgresSchemaDumpTest)
import SMPClient (testServerDBConnectInfo, testStoreDBOpts)
import Simplex.Messaging.Notifications.Server.Store.Migrations (ntfServerMigrations)
import Simplex.Messaging.Server.QueueStore.Postgres.Migrations (serverMigrations)
import XFTPClient (testXFTPDBConnectInfo, xftpPostgresServer, xftpPostgresServer2)
import XFTPClient (testXFTPDBConnectInfo)
#endif
#if defined(dbPostgres) || defined(dbServerPostgres)
@@ -152,19 +153,22 @@ main = do
before (pure $ ASType SQSMemory SMSJournal) smpProxyTests
describe "XFTP" $ do
describe "XFTP server" $
before (pure xftpMemoryServer) xftpServerTests
before (pure $ AFSType SFSMemory) xftpServerTests
describe "XFTP file description" fileDescriptionTests
describe "XFTP CLI (memory)" $
before (pure (xftpMemoryServer, xftpMemoryServer2)) xftpCLIFileTests
describe "XFTP agent" xftpAgentTests
before (pure (AFSType SFSMemory, AFSType SFSMemory)) xftpCLIFileTests
describe "XFTP agent" $
before (pure $ AFSType SFSMemory) xftpAgentTests
#if defined(dbServerPostgres)
around_ (postgressBracket testXFTPDBConnectInfo) $ do
describe "XFTP Postgres store operations" xftpStoreTests
describe "XFTP migration round-trip" xftpMigrationTests
describe "XFTP server (PostgreSQL)" $
before (pure xftpPostgresServer) xftpServerTests
before (pure $ AFSType SFSPostgres) xftpServerTests
describe "XFTP agent (PostgreSQL)" $
before (pure $ AFSType SFSPostgres) xftpAgentTests
describe "XFTP CLI (PostgreSQL)" $
before (pure (xftpPostgresServer, xftpPostgresServer2)) xftpCLIFileTests
before (pure (AFSType SFSPostgres, AFSType SFSPostgres)) xftpCLIFileTests
#endif
#if defined(dbPostgres)
describe "XFTP Web Client" $ xftpWebTests (dropAllSchemasExceptSystem testDBConnectInfo)

View File

@@ -26,7 +26,7 @@ import SMPClient (xit'')
import Simplex.FileTransfer.Client (XFTPClientConfig (..))
import Simplex.FileTransfer.Description (FileChunk (..), FileDescription (..), FileDescriptionURI (..), ValidFileDescription, fileDescriptionURI, kb, mb, qrSizeLimit, pattern ValidFileDescription)
import Simplex.FileTransfer.Protocol (FileParty (..))
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..))
import Simplex.FileTransfer.Server.Env (AFStoreType, XFTPServerConfig (..))
import Simplex.FileTransfer.Server.Store (STMFileStore)
import Simplex.FileTransfer.Transport (XFTPErrorType (AUTH))
import Simplex.FileTransfer.Types (RcvFileId, SndFileId)
@@ -55,44 +55,44 @@ import Fixtures
import Simplex.Messaging.Agent.Store.Postgres.Util (dropAllSchemasExceptSystem)
#endif
xftpAgentTests :: Spec
xftpAgentTests :: SpecWith AFStoreType
xftpAgentTests =
around_ testBracket
#if defined(dbPostgres)
. after_ (dropAllSchemasExceptSystem testDBConnectInfo)
#endif
. describe "agent XFTP API" $ do
it "should send and receive file" $ withXFTPServer testXFTPAgentSendReceive
it "should send and receive file" $ \fsType -> withXFTPServer fsType testXFTPAgentSendReceive
-- uncomment CPP option slow_servers and run hpack to run this test
xit "should send and receive file with slow server responses" $
xit "should send and receive file with slow server responses" $ \_ ->
withXFTPServerCfg testXFTPServerConfig {responseDelay = 500000} $
\_ -> testXFTPAgentSendReceive
it "should send and receive with encrypted local files" testXFTPAgentSendReceiveEncrypted
it "should send and receive large file with a redirect" testXFTPAgentSendReceiveRedirect
it "should send and receive small file without a redirect" testXFTPAgentSendReceiveNoRedirect
describe "sending and receiving with version negotiation" testXFTPAgentSendReceiveMatrix
it "should resume receiving file after restart" testXFTPAgentReceiveRestore
it "should cleanup rcv tmp path after permanent error" testXFTPAgentReceiveCleanup
it "should resume sending file after restart" testXFTPAgentSendRestore
xit'' "should cleanup snd prefix path after permanent error" testXFTPAgentSendCleanup
it "should delete sent file on server" testXFTPAgentDelete
it "should resume deleting file after restart" testXFTPAgentDeleteRestore
it "should send and receive with encrypted local files" $ \fsType -> testXFTPAgentSendReceiveEncrypted fsType
it "should send and receive large file with a redirect" $ \fsType -> testXFTPAgentSendReceiveRedirect fsType
it "should send and receive small file without a redirect" $ \fsType -> testXFTPAgentSendReceiveNoRedirect fsType
describe "sending and receiving with version negotiation" $ beforeWith (const (pure ())) testXFTPAgentSendReceiveMatrix
it "should resume receiving file after restart" $ \_ -> testXFTPAgentReceiveRestore
it "should cleanup rcv tmp path after permanent error" $ \_ -> testXFTPAgentReceiveCleanup
it "should resume sending file after restart" $ \_ -> testXFTPAgentSendRestore
xit'' "should cleanup snd prefix path after permanent error" $ \_ -> testXFTPAgentSendCleanup
it "should delete sent file on server" $ \fsType -> testXFTPAgentDelete fsType
it "should resume deleting file after restart" $ \_ -> testXFTPAgentDeleteRestore
-- TODO when server is fixed to correctly send AUTH error, this test has to be modified to expect AUTH error
it "if file is deleted on server, should limit retries and continue receiving next file" testXFTPAgentDeleteOnServer
it "if file is expired on server, should report error and continue receiving next file" testXFTPAgentExpiredOnServer
it "should request additional recipient IDs when number of recipients exceeds maximum per request" testXFTPAgentRequestAdditionalRecipientIDs
it "if file is deleted on server, should limit retries and continue receiving next file" $ \fsType -> testXFTPAgentDeleteOnServer fsType
it "if file is expired on server, should report error and continue receiving next file" $ \fsType -> testXFTPAgentExpiredOnServer fsType
it "should request additional recipient IDs when number of recipients exceeds maximum per request" $ \fsType -> testXFTPAgentRequestAdditionalRecipientIDs fsType
describe "XFTP server test via agent API" $ do
it "should pass without basic auth" $ testXFTPServerTest Nothing (noAuthSrv testXFTPServer2) `shouldReturn` Nothing
it "should pass without basic auth" $ \_ -> testXFTPServerTest Nothing (noAuthSrv testXFTPServer2) `shouldReturn` Nothing
let srv1 = testXFTPServer2 {keyHash = "1234"}
it "should fail with incorrect fingerprint" $ do
it "should fail with incorrect fingerprint" $ \_ -> do
testXFTPServerTest Nothing (noAuthSrv srv1) `shouldReturn` Just (ProtocolTestFailure TSConnect $ BROKER (B.unpack $ strEncode srv1) $ NETWORK NEUnknownCAError)
describe "server with password" $ do
let auth = Just "abcd"
srv = ProtoServerWithAuth testXFTPServer2
authErr = Just (ProtocolTestFailure TSCreateFile $ XFTP (B.unpack $ strEncode testXFTPServer2) AUTH)
it "should pass with correct password" $ testXFTPServerTest auth (srv auth) `shouldReturn` Nothing
it "should fail without password" $ testXFTPServerTest auth (srv Nothing) `shouldReturn` authErr
it "should fail with incorrect password" $ testXFTPServerTest auth (srv $ Just "wrong") `shouldReturn` authErr
it "should pass with correct password" $ \_ -> testXFTPServerTest auth (srv auth) `shouldReturn` Nothing
it "should fail without password" $ \_ -> testXFTPServerTest auth (srv Nothing) `shouldReturn` authErr
it "should fail with incorrect password" $ \_ -> testXFTPServerTest auth (srv $ Just "wrong") `shouldReturn` authErr
testXFTPServerTest :: HasCallStack => Maybe BasicAuth -> XFTPServerWithAuth -> IO (Maybe ProtocolTestFailure)
testXFTPServerTest newFileBasicAuth srv =
@@ -143,8 +143,8 @@ testXFTPAgentSendReceive = do
rfId <- runRight $ testReceive rcp rfd originalFilePath
xftpDeleteRcvFile rcp rfId
testXFTPAgentSendReceiveEncrypted :: HasCallStack => IO ()
testXFTPAgentSendReceiveEncrypted = withXFTPServer $ do
testXFTPAgentSendReceiveEncrypted :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentSendReceiveEncrypted fsType = withXFTPServer fsType $ do
g <- C.newRandom
filePath <- createRandomFile
s <- LB.readFile filePath
@@ -164,8 +164,8 @@ testXFTPAgentSendReceiveEncrypted = withXFTPServer $ do
rfId <- runRight $ testReceiveCF rcp rfd cfArgs originalFilePath
xftpDeleteRcvFile rcp rfId
testXFTPAgentSendReceiveRedirect :: HasCallStack => IO ()
testXFTPAgentSendReceiveRedirect = withXFTPServer $ do
testXFTPAgentSendReceiveRedirect :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentSendReceiveRedirect fsType = withXFTPServer fsType $ do
--- sender
filePathIn <- createRandomFile
let fileSize = mb 17
@@ -222,8 +222,8 @@ testXFTPAgentSendReceiveRedirect = withXFTPServer $ do
inBytes <- B.readFile filePathIn
B.readFile out `shouldReturn` inBytes
testXFTPAgentSendReceiveNoRedirect :: HasCallStack => IO ()
testXFTPAgentSendReceiveNoRedirect = withXFTPServer $ do
testXFTPAgentSendReceiveNoRedirect :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentSendReceiveNoRedirect fsType = withXFTPServer fsType $ do
--- sender
let fileSize = mb 5
filePathIn <- createRandomFile_ fileSize "testfile"
@@ -506,9 +506,9 @@ testXFTPAgentSendCleanup = withGlobalLogging logCfgNoLogs $ do
doesDirectoryExist prefixPath `shouldReturn` False
doesFileExist encPath `shouldReturn` False
testXFTPAgentDelete :: HasCallStack => IO ()
testXFTPAgentDelete = withGlobalLogging logCfgNoLogs $
withXFTPServer $ do
testXFTPAgentDelete :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentDelete fsType = withGlobalLogging logCfgNoLogs $
withXFTPServer fsType $ do
filePath <- createRandomFile
-- send file
@@ -576,9 +576,9 @@ testXFTPAgentDeleteRestore = withGlobalLogging logCfgNoLogs $ do
rfGet rcp2
liftIO $ rfId' `shouldBe` rfId
testXFTPAgentDeleteOnServer :: HasCallStack => IO ()
testXFTPAgentDeleteOnServer = withGlobalLogging logCfgNoLogs $
withXFTPServer $ do
testXFTPAgentDeleteOnServer :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentDeleteOnServer fsType = withGlobalLogging logCfgNoLogs $
withXFTPServer fsType $ do
filePath1 <- createRandomFile' "testfile1"
-- send file 1
@@ -614,10 +614,9 @@ testXFTPAgentDeleteOnServer = withGlobalLogging logCfgNoLogs $
-- receive file 2
testReceive' rcp rfd2 filePath2
testXFTPAgentExpiredOnServer :: HasCallStack => IO ()
testXFTPAgentExpiredOnServer = withGlobalLogging logCfgNoLogs $ do
let fastExpiration = ExpirationConfig {ttl = 2, checkInterval = 1}
withXFTPServerCfg testXFTPServerConfig {fileExpiration = Just fastExpiration} . const $ do
testXFTPAgentExpiredOnServer :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentExpiredOnServer fsType = withGlobalLogging logCfgNoLogs $
withXFTPServerConfigOn (updateXFTPCfg (cfgFS fsType) $ \c -> c {fileExpiration = Just fastExpiration}) . const $ do
filePath1 <- createRandomFile' "testfile1"
-- send file 1
@@ -652,9 +651,11 @@ testXFTPAgentExpiredOnServer = withGlobalLogging logCfgNoLogs $ do
-- receive file 2 successfully
runRight_ . void $ testReceive' rcp rfd2 filePath2
where
fastExpiration = ExpirationConfig {ttl = 2, checkInterval = 1}
testXFTPAgentRequestAdditionalRecipientIDs :: HasCallStack => IO ()
testXFTPAgentRequestAdditionalRecipientIDs = withXFTPServer $ do
testXFTPAgentRequestAdditionalRecipientIDs :: HasCallStack => AFStoreType -> IO ()
testXFTPAgentRequestAdditionalRecipientIDs fsType = withXFTPServer fsType $ do
filePath <- createRandomFile
-- send file

View File

@@ -11,17 +11,18 @@ import System.FilePath ((</>))
import System.IO.Silently (capture_)
import Test.Hspec hiding (fit, it)
import Util
import XFTPClient (XFTPTestServer (..), testXFTPServerStr, testXFTPServerStr2, xftpServerFiles, xftpServerFiles2)
import Simplex.FileTransfer.Server.Env (AFStoreType)
import XFTPClient (cfgFS, cfgFS2, withXFTPServerConfigOn, testXFTPServerStr, testXFTPServerStr2, xftpServerFiles, xftpServerFiles2)
xftpCLIFileTests :: SpecWith (XFTPTestServer, XFTPTestServer)
xftpCLIFileTests :: SpecWith (AFStoreType, AFStoreType)
xftpCLIFileTests = around_ testBracket $ do
it "should send and receive file" $ \(XFTPTestServer withSrv, _) ->
withSrv id testXFTPCLISendReceive_
it "should send and receive file with 2 servers" $ \(XFTPTestServer withSrv1, XFTPTestServer withSrv2) ->
withSrv1 id $ withSrv2 id testXFTPCLISendReceive2servers_
it "should delete file from 2 servers" $ \(XFTPTestServer withSrv1, XFTPTestServer withSrv2) ->
withSrv1 id $ withSrv2 id testXFTPCLIDelete_
it "prepareChunkSizes should use 2 chunk sizes" $ \(_, _) -> testPrepareChunkSizes
it "should send and receive file" $ \(fsType, _) ->
withXFTPServerConfigOn (cfgFS fsType) $ \_ -> testXFTPCLISendReceive_
it "should send and receive file with 2 servers" $ \(fsType1, fsType2) ->
withXFTPServerConfigOn (cfgFS fsType1) $ \_ -> withXFTPServerConfigOn (cfgFS2 fsType2) $ \_ -> testXFTPCLISendReceive2servers_
it "should delete file from 2 servers" $ \(fsType1, fsType2) ->
withXFTPServerConfigOn (cfgFS fsType1) $ \_ -> withXFTPServerConfigOn (cfgFS2 fsType2) $ \_ -> testXFTPCLIDelete_
it "prepareChunkSizes should use 2 chunk sizes" $ \_ -> testPrepareChunkSizes
testBracket :: IO () -> IO ()
testBracket =

View File

@@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
@@ -8,8 +9,6 @@
module XFTPClient where
import Control.Concurrent (ThreadId, threadDelay)
import Control.Exception (SomeException, catch)
import System.Directory (removeFile)
import Control.Monad (void)
import Data.String (fromString)
import Data.Time.Clock (getCurrentTime)
@@ -18,8 +17,8 @@ import SMPClient (serverBracket)
import Simplex.FileTransfer.Client
import Simplex.FileTransfer.Description
import Simplex.FileTransfer.Server (runXFTPServerBlocking)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), XFTPStoreConfig (..), defaultFileExpiration, defaultInactiveClientExpiration)
import Simplex.FileTransfer.Server.Store (FileStoreClass, STMFileStore)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), XFTPStoreConfig (..), AFStoreType (..), defaultFileExpiration, defaultInactiveClientExpiration)
import Simplex.FileTransfer.Server.Store (FileStoreClass, SFSType (..), STMFileStore)
import Simplex.FileTransfer.Transport (alpnSupportedXFTPhandshakes, supportedFileServerVRange)
import Simplex.Messaging.Protocol (XFTPServer)
import Simplex.Messaging.Transport.HTTP2 (httpALPN)
@@ -33,27 +32,27 @@ import Simplex.Messaging.Agent.Store.Postgres.Options (DBOpts (..))
import Simplex.Messaging.Agent.Store.Shared (MigrationConfirmation (..))
#endif
-- Parameterized server bracket
data AXFTPServerConfig = forall s. FileStoreClass s => AXFTPSrvCfg (XFTPServerConfig s)
newtype XFTPTestServer = XFTPTestServer
{ runServer :: forall a. (forall s. XFTPServerConfig s -> XFTPServerConfig s) -> IO a -> IO a
}
updateXFTPCfg :: AXFTPServerConfig -> (forall s. XFTPServerConfig s -> XFTPServerConfig s) -> AXFTPServerConfig
updateXFTPCfg (AXFTPSrvCfg cfg) f = AXFTPSrvCfg (f cfg)
-- Store-log-dependent agent tests need the bracket + a way to clear server state
type XFTPTestServerClear = (XFTPTestServer, IO ())
cfgFS :: AFStoreType -> AXFTPServerConfig
cfgFS (AFSType fs) = case fs of
SFSMemory -> AXFTPSrvCfg testXFTPServerConfig
#if defined(dbServerPostgres)
SFSPostgres -> AXFTPSrvCfg testXFTPServerConfig {serverStoreCfg = XSCDatabase testXFTPPostgresCfg}
#endif
xftpMemoryServer :: XFTPTestServer
xftpMemoryServer = XFTPTestServer $ \cfgF test -> withXFTPServerCfg (cfgF testXFTPServerConfig) $ \_ -> test
cfgFS2 :: AFStoreType -> AXFTPServerConfig
cfgFS2 (AFSType fs) = case fs of
SFSMemory -> AXFTPSrvCfg testXFTPServerConfig2
#if defined(dbServerPostgres)
SFSPostgres -> AXFTPSrvCfg testXFTPServerConfig2 {serverStoreCfg = XSCDatabase testXFTPPostgresCfg}
#endif
xftpMemoryServerWithLog :: XFTPTestServer
xftpMemoryServerWithLog = XFTPTestServer $ \cfgF test ->
withXFTPServerCfg (cfgF testXFTPServerConfig {serverStoreCfg = XSCMemory (Just testXFTPLogFile), storeLogFile = Just testXFTPLogFile, serverStatsBackupFile = Just testXFTPStatsBackupFile}) $ \_ -> test
xftpMemoryServerClear :: XFTPTestServerClear
xftpMemoryServerClear = (xftpMemoryServerWithLog, removeFile testXFTPLogFile `catch` \(_ :: SomeException) -> pure ())
xftpMemoryServer2 :: XFTPTestServer
xftpMemoryServer2 = XFTPTestServer $ \cfgF test -> withXFTPServerCfg (cfgF testXFTPServerConfig2) $ \_ -> test
withXFTPServerConfigOn :: HasCallStack => AXFTPServerConfig -> (HasCallStack => ThreadId -> IO a) -> IO a
withXFTPServerConfigOn (AXFTPSrvCfg cfg) = withXFTPServerCfg cfg
#if defined(dbServerPostgres)
testXFTPDBConnectInfo :: ConnectInfo
@@ -76,15 +75,6 @@ testXFTPPostgresCfg =
confirmMigrations = MCYesUp
}
xftpPostgresServer :: XFTPTestServer
xftpPostgresServer = XFTPTestServer $ \cfgF test -> withXFTPServerCfg (cfgF testXFTPServerConfig {serverStoreCfg = XSCDatabase testXFTPPostgresCfg}) $ \_ -> test
xftpPostgresServer2 :: XFTPTestServer
xftpPostgresServer2 = XFTPTestServer $ \cfgF test -> withXFTPServerCfg (cfgF testXFTPServerConfig2 {serverStoreCfg = XSCDatabase testXFTPPostgresCfg}) $ \_ -> test
xftpPostgresServerClear :: XFTPTestServerClear
xftpPostgresServerClear = (xftpPostgresServer, clearXFTPPostgresStore)
clearXFTPPostgresStore :: IO ()
clearXFTPPostgresStore = do
let DBOpts {connstr} = dbOpts testXFTPPostgresCfg
@@ -94,23 +84,23 @@ clearXFTPPostgresStore = do
PSQL.close conn
#endif
xftpTest :: HasCallStack => (HasCallStack => XFTPClient -> IO ()) -> XFTPTestServer -> Expectation
xftpTest test (XFTPTestServer withSrv) = withSrv id (testXFTPClient test) `shouldReturn` ()
xftpTest :: HasCallStack => (HasCallStack => XFTPClient -> IO ()) -> AFStoreType -> Expectation
xftpTest test fsType = withXFTPServerConfigOn (cfgFS fsType) (\_ -> testXFTPClient test) `shouldReturn` ()
xftpTestN :: HasCallStack => Int -> (HasCallStack => [XFTPClient] -> IO ()) -> XFTPTestServer -> Expectation
xftpTestN nClients test (XFTPTestServer withSrv) = withSrv id (run nClients []) `shouldReturn` ()
xftpTestN :: HasCallStack => Int -> (HasCallStack => [XFTPClient] -> IO ()) -> AFStoreType -> Expectation
xftpTestN nClients test fsType = withXFTPServerConfigOn (cfgFS fsType) (\_ -> run nClients []) `shouldReturn` ()
where
run :: Int -> [XFTPClient] -> IO ()
run 0 hs = test hs
run n hs = testXFTPClient $ \h -> run (n - 1) (h : hs)
xftpTest2 :: HasCallStack => (HasCallStack => XFTPClient -> XFTPClient -> IO ()) -> XFTPTestServer -> Expectation
xftpTest2 :: HasCallStack => (HasCallStack => XFTPClient -> XFTPClient -> IO ()) -> AFStoreType -> Expectation
xftpTest2 test = xftpTestN 2 _test
where
_test [h1, h2] = test h1 h2
_test _ = error "expected 2 handles"
xftpTest4 :: HasCallStack => (HasCallStack => XFTPClient -> XFTPClient -> XFTPClient -> XFTPClient -> IO ()) -> XFTPTestServer -> Expectation
xftpTest4 :: HasCallStack => (HasCallStack => XFTPClient -> XFTPClient -> XFTPClient -> XFTPClient -> IO ()) -> AFStoreType -> Expectation
xftpTest4 test = xftpTestN 4 _test
where
_test [h1, h2, h3, h4] = test h1 h2 h3 h4
@@ -125,11 +115,11 @@ withXFTPServerCfg cfg =
withXFTPServerCfgNoALPN :: (HasCallStack, FileStoreClass s) => XFTPServerConfig s -> (HasCallStack => ThreadId -> IO a) -> IO a
withXFTPServerCfgNoALPN cfg = withXFTPServerCfg cfg {transportConfig = (transportConfig cfg) {serverALPN = Nothing}}
withXFTPServer :: HasCallStack => IO a -> IO a
withXFTPServer = withXFTPServerCfg testXFTPServerConfig . const
withXFTPServer :: HasCallStack => AFStoreType -> IO a -> IO a
withXFTPServer fsType = withXFTPServerConfigOn (cfgFS fsType) . const
withXFTPServer2 :: HasCallStack => IO a -> IO a
withXFTPServer2 = withXFTPServerCfg testXFTPServerConfig {xftpPort = xftpTestPort2, filesPath = xftpServerFiles2} . const
withXFTPServer2 :: HasCallStack => AFStoreType -> IO a -> IO a
withXFTPServer2 fsType = withXFTPServerConfigOn (cfgFS2 fsType) . const
withXFTPServerStoreLogOn :: HasCallStack => (HasCallStack => ThreadId -> IO a) -> IO a
withXFTPServerStoreLogOn = withXFTPServerCfg testXFTPServerConfig {serverStoreCfg = XSCMemory (Just testXFTPLogFile), storeLogFile = Just testXFTPLogFile, serverStatsBackupFile = Just testXFTPStatsBackupFile}

View File

@@ -31,7 +31,7 @@ import ServerTests (logSize)
import Simplex.FileTransfer.Client
import Simplex.FileTransfer.Description (kb)
import Simplex.FileTransfer.Protocol (FileInfo (..), XFTPFileId, xftpBlockSize)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..))
import Simplex.FileTransfer.Server.Env (AFStoreType, XFTPServerConfig (..))
import Simplex.FileTransfer.Transport (XFTPClientHandshake (..), XFTPClientHello (..), XFTPErrorType (..), XFTPRcvChunkSpec (..), XFTPServerHandshake (..), pattern VersionXFTP)
import Simplex.Messaging.Client (ProtocolClientError (..))
import qualified Simplex.Messaging.Crypto as C
@@ -52,7 +52,7 @@ import UnliftIO.STM
import Util
import XFTPClient
xftpServerTests :: SpecWith XFTPTestServer
xftpServerTests :: SpecWith AFStoreType
xftpServerTests =
before_ (createDirectoryIfMissing False xftpServerFiles) . after_ (removeDirectoryRecursive xftpServerFiles) $ do
describe "XFTP file chunk delivery" $ do
@@ -103,10 +103,10 @@ createTestChunk fp = do
readChunk :: XFTPFileId -> IO ByteString
readChunk sId = B.readFile (xftpServerFiles </> B.unpack (B64.encode $ unEntityId sId))
testFileChunkDelivery :: XFTPTestServer -> Expectation
testFileChunkDelivery :: AFStoreType -> Expectation
testFileChunkDelivery = xftpTest $ \c -> runRight_ $ runTestFileChunkDelivery c c
testFileChunkDelivery2 :: XFTPTestServer -> Expectation
testFileChunkDelivery2 :: AFStoreType -> Expectation
testFileChunkDelivery2 = xftpTest2 $ \s r -> runRight_ $ runTestFileChunkDelivery s r
runTestFileChunkDelivery :: XFTPClient -> XFTPClient -> ExceptT XFTPClientError IO ()
@@ -129,7 +129,7 @@ runTestFileChunkDelivery s r = do
downloadXFTPChunk g r rpKey rId $ XFTPRcvChunkSpec "tests/tmp/received_chunk1" chSize digest
liftIO $ B.readFile "tests/tmp/received_chunk1" `shouldReturn` bytes
testFileChunkDeliveryAddRecipients :: XFTPTestServer -> Expectation
testFileChunkDeliveryAddRecipients :: AFStoreType -> Expectation
testFileChunkDeliveryAddRecipients = xftpTest4 $ \s r1 r2 r3 -> runRight_ $ do
g <- liftIO C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g
@@ -150,10 +150,10 @@ testFileChunkDeliveryAddRecipients = xftpTest4 $ \s r1 r2 r3 -> runRight_ $ do
testReceiveChunk r2 rpKey2 rId2 "tests/tmp/received_chunk2"
testReceiveChunk r3 rpKey3 rId3 "tests/tmp/received_chunk3"
testFileChunkDelete :: XFTPTestServer -> Expectation
testFileChunkDelete :: AFStoreType -> Expectation
testFileChunkDelete = xftpTest $ \c -> runRight_ $ runTestFileChunkDelete c c
testFileChunkDelete2 :: XFTPTestServer -> Expectation
testFileChunkDelete2 :: AFStoreType -> Expectation
testFileChunkDelete2 = xftpTest2 $ \s r -> runRight_ $ runTestFileChunkDelete s r
runTestFileChunkDelete :: XFTPClient -> XFTPClient -> ExceptT XFTPClientError IO ()
@@ -179,10 +179,10 @@ runTestFileChunkDelete s r = do
deleteXFTPChunk s spKey sId
`catchError` (liftIO . (`shouldBe` PCEProtocolError AUTH))
testFileChunkAck :: XFTPTestServer -> Expectation
testFileChunkAck :: AFStoreType -> Expectation
testFileChunkAck = xftpTest $ \c -> runRight_ $ runTestFileChunkAck c c
testFileChunkAck2 :: XFTPTestServer -> Expectation
testFileChunkAck2 :: AFStoreType -> Expectation
testFileChunkAck2 = xftpTest2 $ \s r -> runRight_ $ runTestFileChunkAck s r
runTestFileChunkAck :: XFTPClient -> XFTPClient -> ExceptT XFTPClientError IO ()
@@ -206,7 +206,7 @@ runTestFileChunkAck s r = do
ackXFTPChunk r rpKey rId
`catchError` (liftIO . (`shouldBe` PCEProtocolError AUTH))
testWrongChunkSize :: XFTPTestServer -> Expectation
testWrongChunkSize :: AFStoreType -> Expectation
testWrongChunkSize = xftpTest $ \c -> do
g <- C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g
@@ -218,8 +218,8 @@ testWrongChunkSize = xftpTest $ \c -> do
void (createXFTPChunk c spKey file [rcvKey] Nothing)
`catchError` (liftIO . (`shouldBe` PCEProtocolError SIZE))
testFileChunkExpiration :: XFTPTestServer -> Expectation
testFileChunkExpiration _ = withXFTPServerCfg testXFTPServerConfig {fileExpiration} $
testFileChunkExpiration :: AFStoreType -> Expectation
testFileChunkExpiration fsType = withXFTPServerConfigOn (updateXFTPCfg (cfgFS fsType) $ \c -> c {fileExpiration}) $
\_ -> testXFTPClient $ \c -> runRight_ $ do
g <- liftIO C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g
@@ -242,8 +242,8 @@ testFileChunkExpiration _ = withXFTPServerCfg testXFTPServerConfig {fileExpirati
where
fileExpiration = Just ExpirationConfig {ttl = 1, checkInterval = 1}
testInactiveClientExpiration :: XFTPTestServer -> Expectation
testInactiveClientExpiration _ = withXFTPServerCfg testXFTPServerConfig {inactiveClientExpiration} $ \_ -> runRight_ $ do
testInactiveClientExpiration :: AFStoreType -> Expectation
testInactiveClientExpiration fsType = withXFTPServerConfigOn (updateXFTPCfg (cfgFS fsType) $ \c -> c {inactiveClientExpiration}) $ \_ -> runRight_ $ do
disconnected <- newEmptyTMVarIO
ts <- liftIO getCurrentTime
c <- ExceptT $ getXFTPClient (1, testXFTPServer, Nothing) testXFTPClientConfig [] ts (\_ -> atomically $ putTMVar disconnected ())
@@ -258,8 +258,8 @@ testInactiveClientExpiration _ = withXFTPServerCfg testXFTPServerConfig {inactiv
where
inactiveClientExpiration = Just ExpirationConfig {ttl = 1, checkInterval = 1}
testFileStorageQuota :: XFTPTestServer -> Expectation
testFileStorageQuota _ = withXFTPServerCfg testXFTPServerConfig {fileSizeQuota = Just $ chSize * 2} $
testFileStorageQuota :: AFStoreType -> Expectation
testFileStorageQuota fsType = withXFTPServerConfigOn (updateXFTPCfg (cfgFS fsType) $ \c -> c {fileSizeQuota = Just $ chSize * 2}) $
\_ -> testXFTPClient $ \c -> runRight_ $ do
g <- liftIO C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g
@@ -286,7 +286,7 @@ testFileStorageQuota _ = withXFTPServerCfg testXFTPServerConfig {fileSizeQuota =
uploadXFTPChunk c spKey sId3 chunkSpec
download rId3
testFileLog :: XFTPTestServer -> Expectation
testFileLog :: AFStoreType -> Expectation
testFileLog _ = do
g <- C.newRandom
bytes <- liftIO $ createTestChunk testChunkPath
@@ -378,9 +378,9 @@ testFileLog _ = do
downloadXFTPChunk g c rpKey rId $ XFTPRcvChunkSpec "tests/tmp/received_chunk1" chSize digest
liftIO $ B.readFile "tests/tmp/received_chunk1" `shouldReturn` bytes
testFileBasicAuth :: Bool -> Maybe BasicAuth -> Maybe BasicAuth -> Bool -> XFTPTestServer -> IO ()
testFileBasicAuth allowNewFiles newFileBasicAuth clntAuth success _ =
withXFTPServerCfg testXFTPServerConfig {allowNewFiles, newFileBasicAuth} $
testFileBasicAuth :: Bool -> Maybe BasicAuth -> Maybe BasicAuth -> Bool -> AFStoreType -> IO ()
testFileBasicAuth allowNewFiles newFileBasicAuth clntAuth success fsType =
withXFTPServerConfigOn (updateXFTPCfg (cfgFS fsType) $ \c -> c {allowNewFiles, newFileBasicAuth}) $
\_ -> testXFTPClient $ \c -> do
g <- C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g
@@ -400,9 +400,9 @@ testFileBasicAuth allowNewFiles newFileBasicAuth clntAuth success _ =
void (createXFTPChunk c spKey file [rcvKey] clntAuth)
`catchError` (liftIO . (`shouldBe` PCEProtocolError AUTH))
testFileSkipCommitted :: XFTPTestServer -> IO ()
testFileSkipCommitted _ =
withXFTPServerCfg testXFTPServerConfig $
testFileSkipCommitted :: AFStoreType -> IO ()
testFileSkipCommitted fsType =
withXFTPServerConfigOn (cfgFS fsType) $
\_ -> testXFTPClient $ \c -> do
g <- C.newRandom
(sndKey, spKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g