2025-01-10 15:27:29 +04:00
|
|
|
{-# LANGUAGE CPP #-}
|
2021-07-07 22:46:38 +01:00
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
2021-08-05 20:51:48 +01:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2021-07-07 22:46:38 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
|
|
{-# LANGUAGE OverloadedLists #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2024-03-05 20:27:00 +04:00
|
|
|
{-# LANGUAGE PatternSynonyms #-}
|
2023-01-31 11:07:48 +00:00
|
|
|
{-# LANGUAGE RankNTypes #-}
|
2024-03-09 03:09:12 +04:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
2021-08-05 20:51:48 +01:00
|
|
|
{-# LANGUAGE TypeApplications #-}
|
2023-08-25 04:56:37 +08:00
|
|
|
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
|
|
|
|
|
2021-07-07 22:46:38 +01:00
|
|
|
module ChatClient where
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
import ChatTests.DBUtils
|
2023-01-31 11:07:48 +00:00
|
|
|
import Control.Concurrent (forkIOWithUnmask, killThread, threadDelay)
|
2021-07-07 22:46:38 +01:00
|
|
|
import Control.Concurrent.Async
|
2021-08-05 20:51:48 +01:00
|
|
|
import Control.Concurrent.STM
|
|
|
|
import Control.Exception (bracket, bracket_)
|
2023-08-25 04:56:37 +08:00
|
|
|
import Control.Monad
|
2021-07-07 22:46:38 +01:00
|
|
|
import Control.Monad.Except
|
2024-02-20 13:56:31 +04:00
|
|
|
import Control.Monad.Reader
|
2022-10-14 13:06:33 +01:00
|
|
|
import Data.Functor (($>))
|
2022-04-25 16:30:21 +01:00
|
|
|
import Data.List (dropWhileEnd, find)
|
2023-12-19 10:26:01 +00:00
|
|
|
import Data.Maybe (isNothing)
|
2022-03-13 19:34:03 +00:00
|
|
|
import qualified Data.Text as T
|
2021-08-05 20:51:48 +01:00
|
|
|
import Network.Socket
|
2021-07-07 22:46:38 +01:00
|
|
|
import Simplex.Chat
|
2024-11-18 18:44:28 +00:00
|
|
|
import Simplex.Chat.Controller (ChatCommand (..), ChatConfig (..), ChatController (..), ChatDatabase (..), ChatLogLevel (..), defaultSimpleNetCfg)
|
2022-04-10 17:13:06 +01:00
|
|
|
import Simplex.Chat.Core
|
2024-12-20 16:54:24 +04:00
|
|
|
import Simplex.Chat.Library.Commands
|
2021-07-07 22:46:38 +01:00
|
|
|
import Simplex.Chat.Options
|
2025-01-10 15:27:29 +04:00
|
|
|
import Simplex.Chat.Options.DB
|
2024-03-10 18:57:57 +04:00
|
|
|
import Simplex.Chat.Protocol (currentChatVersion, pqEncryptionCompressionVersion)
|
2021-07-07 22:46:38 +01:00
|
|
|
import Simplex.Chat.Store
|
2023-06-18 10:20:11 +01:00
|
|
|
import Simplex.Chat.Store.Profiles
|
2022-01-21 11:09:33 +00:00
|
|
|
import Simplex.Chat.Terminal
|
|
|
|
import Simplex.Chat.Terminal.Output (newChatTerminal)
|
2024-03-05 20:27:00 +04:00
|
|
|
import Simplex.Chat.Types
|
2023-03-16 14:12:19 +04:00
|
|
|
import Simplex.FileTransfer.Description (kb, mb)
|
|
|
|
import Simplex.FileTransfer.Server (runXFTPServerBlocking)
|
2024-10-07 23:30:52 +01:00
|
|
|
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), defaultFileExpiration)
|
2024-05-15 15:30:05 +04:00
|
|
|
import Simplex.FileTransfer.Transport (supportedFileServerVRange)
|
2024-03-21 19:00:19 +00:00
|
|
|
import Simplex.Messaging.Agent (disposeAgentClient)
|
2021-08-02 20:10:24 +01:00
|
|
|
import Simplex.Messaging.Agent.Env.SQLite
|
2024-03-10 18:57:57 +04:00
|
|
|
import Simplex.Messaging.Agent.Protocol (currentSMPAgentVersion, duplexHandshakeSMPAgentVersion, pqdrSMPAgentVersion, supportedSMPAgentVRange)
|
2021-08-14 21:04:51 +01:00
|
|
|
import Simplex.Messaging.Agent.RetryInterval
|
2025-01-20 17:41:48 +04:00
|
|
|
import Simplex.Messaging.Agent.Store.Interface (closeDBStore)
|
2025-01-10 15:27:29 +04:00
|
|
|
import Simplex.Messaging.Agent.Store.Shared (MigrationConfirmation (..), MigrationError)
|
|
|
|
import qualified Simplex.Messaging.Agent.Store.DB as DB
|
2024-05-31 23:41:20 +01:00
|
|
|
import Simplex.Messaging.Client (ProtocolClientConfig (..))
|
2024-05-15 15:30:05 +04:00
|
|
|
import Simplex.Messaging.Client.Agent (defaultSMPClientAgentConfig)
|
2024-04-22 20:46:48 +04:00
|
|
|
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange)
|
2024-03-10 18:57:57 +04:00
|
|
|
import qualified Simplex.Messaging.Crypto.Ratchet as CR
|
2024-07-04 07:58:13 +01:00
|
|
|
import Simplex.Messaging.Protocol (srvHostnamesSMPClientVersion)
|
2021-08-05 20:51:48 +01:00
|
|
|
import Simplex.Messaging.Server (runSMPServerBlocking)
|
2025-02-23 22:21:10 +00:00
|
|
|
import Simplex.Messaging.Server.Env.STM (ServerConfig (..), StartOptions (..), defaultMessageExpiration, defaultIdleQueueInterval, defaultNtfExpiration, defaultInactiveClientExpiration)
|
2024-11-02 19:51:11 +02:00
|
|
|
import Simplex.Messaging.Server.MsgStore.Types (AMSType (..), SMSType (..))
|
2021-08-05 20:51:48 +01:00
|
|
|
import Simplex.Messaging.Transport
|
2024-10-07 23:30:52 +01:00
|
|
|
import Simplex.Messaging.Transport.Server (ServerCredentials (..), defaultTransportServerConfig)
|
2022-06-09 14:52:12 +01:00
|
|
|
import Simplex.Messaging.Version
|
2024-03-05 20:27:00 +04:00
|
|
|
import Simplex.Messaging.Version.Internal
|
2023-01-31 11:07:48 +00:00
|
|
|
import System.Directory (createDirectoryIfMissing, removeDirectoryRecursive)
|
2021-07-07 22:46:38 +01:00
|
|
|
import qualified System.Terminal as C
|
2021-08-05 20:51:48 +01:00
|
|
|
import System.Terminal.Internal (VirtualTerminal (..), VirtualTerminalSettings (..), withVirtualTerminal)
|
|
|
|
import System.Timeout (timeout)
|
2023-01-31 11:07:48 +00:00
|
|
|
import Test.Hspec (Expectation, HasCallStack, shouldReturn)
|
2025-01-10 15:27:29 +04:00
|
|
|
#if defined(dbPostgres)
|
|
|
|
import Database.PostgreSQL.Simple (ConnectInfo (..), defaultConnectInfo)
|
|
|
|
#else
|
|
|
|
import Data.ByteArray (ScrubbedBytes)
|
2025-01-24 09:44:53 +00:00
|
|
|
import qualified Data.Map.Strict as M
|
2025-01-24 17:49:31 +04:00
|
|
|
import Simplex.Messaging.Agent.Client (agentClientStore)
|
2025-01-24 09:44:53 +00:00
|
|
|
import Simplex.Messaging.Agent.Store.Common (withConnection)
|
2025-01-10 15:27:29 +04:00
|
|
|
import System.FilePath ((</>))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(dbPostgres)
|
2025-01-20 17:41:48 +04:00
|
|
|
testDBConnstr :: String
|
|
|
|
testDBConnstr = "postgresql://test_chat_user@/test_chat_db"
|
2025-01-10 15:27:29 +04:00
|
|
|
|
|
|
|
testDBConnectInfo :: ConnectInfo
|
|
|
|
testDBConnectInfo =
|
|
|
|
defaultConnectInfo {
|
2025-01-20 17:41:48 +04:00
|
|
|
connectUser = "test_chat_user",
|
|
|
|
connectDatabase = "test_chat_db"
|
2025-01-10 15:27:29 +04:00
|
|
|
}
|
|
|
|
#endif
|
2021-07-07 22:46:38 +01:00
|
|
|
|
2021-08-05 20:51:48 +01:00
|
|
|
serverPort :: ServiceName
|
2023-01-31 11:07:48 +00:00
|
|
|
serverPort = "7001"
|
2021-08-05 20:51:48 +01:00
|
|
|
|
2022-06-06 16:23:47 +01:00
|
|
|
testOpts :: ChatOpts
|
|
|
|
testOpts =
|
2021-07-07 22:46:38 +01:00
|
|
|
ChatOpts
|
2023-12-29 23:15:14 +02:00
|
|
|
{ coreOptions = testCoreOpts,
|
2022-04-10 17:13:06 +01:00
|
|
|
chatCmd = "",
|
2022-05-13 19:44:03 +01:00
|
|
|
chatCmdDelay = 3,
|
2024-01-20 14:59:13 +00:00
|
|
|
chatCmdLog = CCLNone,
|
2022-06-06 16:23:47 +01:00
|
|
|
chatServerPort = Nothing,
|
2022-12-26 22:24:34 +00:00
|
|
|
optFilesFolder = Nothing,
|
2024-03-14 10:59:20 +04:00
|
|
|
optTempDirectory = Nothing,
|
2023-05-15 12:28:53 +02:00
|
|
|
showReactions = True,
|
2022-11-26 22:39:56 +00:00
|
|
|
allowInstantFiles = True,
|
2023-06-16 13:43:06 +01:00
|
|
|
autoAcceptFileSize = 0,
|
2023-05-03 17:40:11 +02:00
|
|
|
muteNotifications = True,
|
2023-12-03 15:42:26 +00:00
|
|
|
markRead = True,
|
2022-06-06 16:23:47 +01:00
|
|
|
maintenance = False
|
2021-07-07 22:46:38 +01:00
|
|
|
}
|
|
|
|
|
2023-12-29 23:15:14 +02:00
|
|
|
testCoreOpts :: CoreChatOpts
|
2024-01-17 15:20:13 +00:00
|
|
|
testCoreOpts =
|
|
|
|
CoreChatOpts
|
2025-01-10 15:27:29 +04:00
|
|
|
{
|
|
|
|
dbOptions = ChatDbOpts
|
|
|
|
#if defined(dbPostgres)
|
2025-01-20 17:41:48 +04:00
|
|
|
{ dbConnstr = testDBConnstr,
|
2025-01-10 15:27:29 +04:00
|
|
|
-- dbSchemaPrefix is not used in tests (except bot tests where it's redefined),
|
|
|
|
-- instead different schema prefix is passed per client so that single test database is used
|
|
|
|
dbSchemaPrefix = ""
|
|
|
|
#else
|
|
|
|
{ dbFilePrefix = "./simplex_v1", -- dbFilePrefix is not used in tests (except bot tests where it's redefined)
|
|
|
|
dbKey = "", -- dbKey = "this is a pass-phrase to encrypt the database",
|
2025-01-24 09:44:53 +00:00
|
|
|
trackQueries = DB.TQAll,
|
2025-01-10 15:27:29 +04:00
|
|
|
vacuumOnMigration = True
|
|
|
|
#endif
|
|
|
|
},
|
2024-11-18 18:44:28 +00:00
|
|
|
smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001"],
|
|
|
|
xftpServers = ["xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002"],
|
2024-05-31 23:41:20 +01:00
|
|
|
simpleNetCfg = defaultSimpleNetCfg,
|
2024-01-17 15:20:13 +00:00
|
|
|
logLevel = CLLImportant,
|
|
|
|
logConnections = False,
|
|
|
|
logServerHosts = False,
|
|
|
|
logAgent = Nothing,
|
|
|
|
logFile = Nothing,
|
|
|
|
tbqSize = 16,
|
2025-03-05 11:20:30 +00:00
|
|
|
deviceName = Nothing,
|
2024-06-16 20:24:37 -07:00
|
|
|
highlyAvailable = False,
|
2025-01-10 15:27:29 +04:00
|
|
|
yesToUpMigrations = False
|
2024-01-17 15:20:13 +00:00
|
|
|
}
|
2023-12-29 23:15:14 +02:00
|
|
|
|
2025-01-10 15:27:29 +04:00
|
|
|
#if !defined(dbPostgres)
|
2023-12-09 21:59:40 +00:00
|
|
|
getTestOpts :: Bool -> ScrubbedBytes -> ChatOpts
|
2025-01-10 15:27:29 +04:00
|
|
|
getTestOpts maintenance dbKey = testOpts {maintenance, coreOptions = testCoreOpts {dbOptions = (dbOptions testCoreOpts) {dbKey}}}
|
|
|
|
#endif
|
2023-02-18 17:39:16 +00:00
|
|
|
|
2021-07-07 22:46:38 +01:00
|
|
|
termSettings :: VirtualTerminalSettings
|
|
|
|
termSettings =
|
|
|
|
VirtualTerminalSettings
|
|
|
|
{ virtualType = "xterm",
|
2023-11-08 22:13:52 +02:00
|
|
|
virtualWindowSize = pure C.Size {height = 24, width = 2250},
|
2021-07-07 22:46:38 +01:00
|
|
|
virtualEvent = retry,
|
|
|
|
virtualInterrupt = retry
|
|
|
|
}
|
|
|
|
|
2021-08-05 20:51:48 +01:00
|
|
|
data TestCC = TestCC
|
|
|
|
{ chatController :: ChatController,
|
|
|
|
virtualTerminal :: VirtualTerminal,
|
|
|
|
chatAsync :: Async (),
|
|
|
|
termAsync :: Async (),
|
2023-05-24 16:14:41 +04:00
|
|
|
termQ :: TQueue String,
|
|
|
|
printOutput :: Bool
|
2021-08-05 20:51:48 +01:00
|
|
|
}
|
2021-07-07 22:46:38 +01:00
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
aCfg :: AgentConfig
|
2023-02-28 23:26:08 +00:00
|
|
|
aCfg = (agentConfig defaultChatConfig) {tbqSize = 16}
|
2021-08-02 20:10:24 +01:00
|
|
|
|
2022-06-09 14:52:12 +01:00
|
|
|
testAgentCfg :: AgentConfig
|
2023-03-30 18:36:39 +04:00
|
|
|
testAgentCfg =
|
|
|
|
aCfg
|
2024-06-05 21:02:13 +04:00
|
|
|
{ reconnectInterval = (reconnectInterval aCfg) {initialInterval = 50000}
|
2023-03-30 18:36:39 +04:00
|
|
|
}
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2024-07-04 07:58:13 +01:00
|
|
|
testAgentCfgSlow :: AgentConfig
|
|
|
|
testAgentCfgSlow =
|
|
|
|
testAgentCfg
|
|
|
|
{ smpClientVRange = mkVersionRange (Version 1) srvHostnamesSMPClientVersion, -- v2
|
|
|
|
smpAgentVRange = mkVersionRange duplexHandshakeSMPAgentVersion pqdrSMPAgentVersion, -- v5
|
2025-01-20 18:43:25 +00:00
|
|
|
smpCfg = (smpCfg testAgentCfg) {serverVRange = mkVersionRange minClientSMPRelayVersion sendingProxySMPVersion} -- v8
|
2024-07-04 07:58:13 +01:00
|
|
|
}
|
|
|
|
|
2022-06-09 14:52:12 +01:00
|
|
|
testCfg :: ChatConfig
|
|
|
|
testCfg =
|
2021-08-02 20:10:24 +01:00
|
|
|
defaultChatConfig
|
2022-06-09 14:52:12 +01:00
|
|
|
{ agentConfig = testAgentCfg,
|
2023-07-13 23:48:25 +01:00
|
|
|
showReceipts = False,
|
2023-02-28 23:26:08 +00:00
|
|
|
testView = True,
|
2024-02-20 13:56:31 +04:00
|
|
|
tbqSize = 16
|
2021-08-02 20:10:24 +01:00
|
|
|
}
|
|
|
|
|
2024-07-04 07:58:13 +01:00
|
|
|
testCfgSlow :: ChatConfig
|
|
|
|
testCfgSlow = testCfg {agentConfig = testAgentCfgSlow}
|
|
|
|
|
2023-12-24 13:27:51 +00:00
|
|
|
testAgentCfgVPrev :: AgentConfig
|
|
|
|
testAgentCfgVPrev =
|
|
|
|
testAgentCfg
|
2024-03-05 20:27:00 +04:00
|
|
|
{ smpClientVRange = prevRange $ smpClientVRange testAgentCfg,
|
2024-04-22 20:46:48 +04:00
|
|
|
smpAgentVRange = prevRange supportedSMPAgentVRange,
|
|
|
|
e2eEncryptVRange = prevRange supportedE2EEncryptVRange,
|
2023-12-24 13:27:51 +00:00
|
|
|
smpCfg = (smpCfg testAgentCfg) {serverVRange = prevRange $ serverVRange $ smpCfg testAgentCfg}
|
|
|
|
}
|
|
|
|
|
2024-03-10 18:57:57 +04:00
|
|
|
testAgentCfgVNext :: AgentConfig
|
|
|
|
testAgentCfgVNext =
|
|
|
|
testAgentCfg
|
|
|
|
{ smpClientVRange = nextRange $ smpClientVRange testAgentCfg,
|
2024-04-22 20:46:48 +04:00
|
|
|
smpAgentVRange = mkVersionRange duplexHandshakeSMPAgentVersion $ max pqdrSMPAgentVersion currentSMPAgentVersion,
|
|
|
|
e2eEncryptVRange = mkVersionRange CR.kdfX3DHE2EEncryptVersion $ max CR.pqRatchetE2EEncryptVersion CR.currentE2EEncryptVersion,
|
2024-03-10 18:57:57 +04:00
|
|
|
smpCfg = (smpCfg testAgentCfg) {serverVRange = nextRange $ serverVRange $ smpCfg testAgentCfg}
|
|
|
|
}
|
|
|
|
|
2022-06-09 14:52:12 +01:00
|
|
|
testAgentCfgV1 :: AgentConfig
|
|
|
|
testAgentCfgV1 =
|
|
|
|
testAgentCfg
|
2023-12-24 13:27:51 +00:00
|
|
|
{ smpClientVRange = v1Range,
|
2024-04-22 20:46:48 +04:00
|
|
|
smpAgentVRange = versionToRange duplexHandshakeSMPAgentVersion,
|
|
|
|
e2eEncryptVRange = versionToRange CR.kdfX3DHE2EEncryptVersion,
|
2025-01-20 18:43:25 +00:00
|
|
|
smpCfg = (smpCfg testAgentCfg) {serverVRange = versionToRange minClientSMPRelayVersion}
|
2023-12-24 13:27:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
testCfgVPrev :: ChatConfig
|
|
|
|
testCfgVPrev =
|
|
|
|
testCfg
|
2024-04-22 20:46:48 +04:00
|
|
|
{ chatVRange = prevRange $ chatVRange testCfg,
|
2023-12-24 13:27:51 +00:00
|
|
|
agentConfig = testAgentCfgVPrev
|
2022-06-09 14:52:12 +01:00
|
|
|
}
|
|
|
|
|
2024-03-10 18:57:57 +04:00
|
|
|
testCfgVNext :: ChatConfig
|
|
|
|
testCfgVNext =
|
|
|
|
testCfg
|
2024-04-22 20:46:48 +04:00
|
|
|
{ chatVRange = mkVersionRange initialChatVersion $ max pqEncryptionCompressionVersion currentChatVersion,
|
2024-03-10 18:57:57 +04:00
|
|
|
agentConfig = testAgentCfgVNext
|
|
|
|
}
|
|
|
|
|
2022-06-09 14:52:12 +01:00
|
|
|
testCfgV1 :: ChatConfig
|
2023-12-24 13:27:51 +00:00
|
|
|
testCfgV1 =
|
|
|
|
testCfg
|
2024-04-22 20:46:48 +04:00
|
|
|
{ chatVRange = v1Range,
|
2023-12-24 13:27:51 +00:00
|
|
|
agentConfig = testAgentCfgV1
|
|
|
|
}
|
|
|
|
|
2024-03-05 20:27:00 +04:00
|
|
|
prevRange :: VersionRange v -> VersionRange v
|
|
|
|
prevRange vr = vr {maxVersion = max (minVersion vr) (prevVersion $ maxVersion vr)}
|
2023-12-24 13:27:51 +00:00
|
|
|
|
2024-03-10 18:57:57 +04:00
|
|
|
nextRange :: VersionRange v -> VersionRange v
|
|
|
|
nextRange vr = vr {maxVersion = max (minVersion vr) (nextVersion $ maxVersion vr)}
|
|
|
|
|
2024-03-05 20:27:00 +04:00
|
|
|
v1Range :: VersionRange v
|
|
|
|
v1Range = mkVersionRange (Version 1) (Version 1)
|
|
|
|
|
|
|
|
prevVersion :: Version v -> Version v
|
|
|
|
prevVersion (Version v) = Version (v - 1)
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2024-03-10 18:57:57 +04:00
|
|
|
nextVersion :: Version v -> Version v
|
|
|
|
nextVersion (Version v) = Version (v + 1)
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
createTestChat :: TestParams -> ChatConfig -> ChatOpts -> String -> Profile -> IO TestCC
|
|
|
|
createTestChat ps cfg opts@ChatOpts {coreOptions} dbPrefix profile = do
|
|
|
|
Right db@ChatDatabase {chatStore, agentStore} <- createDatabase ps coreOptions dbPrefix
|
2025-01-10 15:27:29 +04:00
|
|
|
insertUser agentStore
|
2023-01-13 13:54:07 +04:00
|
|
|
Right user <- withTransaction chatStore $ \db' -> runExceptT $ createUserRecord db' (AgentUserId 1) profile True
|
2025-02-15 16:18:34 +00:00
|
|
|
startTestChat_ ps db cfg opts user
|
2022-04-25 16:30:21 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
startTestChat :: TestParams -> ChatConfig -> ChatOpts -> String -> IO TestCC
|
|
|
|
startTestChat ps cfg opts@ChatOpts {coreOptions} dbPrefix = do
|
|
|
|
Right db@ChatDatabase {chatStore} <- createDatabase ps coreOptions dbPrefix
|
2022-09-23 19:22:56 +01:00
|
|
|
Just user <- find activeUser <$> withTransaction chatStore getUsers
|
2025-02-15 16:18:34 +00:00
|
|
|
startTestChat_ ps db cfg opts user
|
2022-04-25 16:30:21 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
createDatabase :: TestParams -> CoreChatOpts -> String -> IO (Either MigrationError ChatDatabase)
|
2025-01-10 15:27:29 +04:00
|
|
|
#if defined(dbPostgres)
|
2025-01-24 09:44:53 +00:00
|
|
|
createDatabase _params CoreChatOpts {dbOptions} dbPrefix = do
|
2025-01-10 15:27:29 +04:00
|
|
|
createChatDatabase dbOptions {dbSchemaPrefix = "client_" <> dbPrefix} MCError
|
|
|
|
|
|
|
|
insertUser :: DBStore -> IO ()
|
|
|
|
insertUser st = withTransaction st (`DB.execute_` "INSERT INTO users DEFAULT VALUES")
|
|
|
|
#else
|
2025-01-24 09:44:53 +00:00
|
|
|
createDatabase TestParams {tmpPath} CoreChatOpts {dbOptions} dbPrefix = do
|
|
|
|
createChatDatabase dbOptions {dbFilePrefix = tmpPath </> dbPrefix} MCError
|
2025-01-10 15:27:29 +04:00
|
|
|
|
|
|
|
insertUser :: DBStore -> IO ()
|
|
|
|
insertUser st = withTransaction st (`DB.execute_` "INSERT INTO users (user_id) VALUES (1)")
|
|
|
|
#endif
|
|
|
|
|
2025-02-15 16:18:34 +00:00
|
|
|
startTestChat_ :: TestParams -> ChatDatabase -> ChatConfig -> ChatOpts -> User -> IO TestCC
|
2025-02-23 22:21:10 +00:00
|
|
|
startTestChat_ TestParams {printOutput} db cfg opts@ChatOpts {maintenance} user = do
|
2021-07-07 22:46:38 +01:00
|
|
|
t <- withVirtualTerminal termSettings pure
|
2023-10-11 09:50:11 +01:00
|
|
|
ct <- newChatTerminal t opts
|
2023-12-23 13:06:59 +00:00
|
|
|
cc <- newChatController db (Just user) cfg opts False
|
2024-02-20 13:56:31 +04:00
|
|
|
void $ execChatCommand' (SetTempFolder "tests/tmp/tmp") `runReaderT` cc
|
2023-12-03 15:42:26 +00:00
|
|
|
chatAsync <- async . runSimplexChat opts user cc $ \_u cc' -> runChatTerminal ct cc' opts
|
2025-02-23 22:21:10 +00:00
|
|
|
atomically . unless maintenance $ readTVar (agentAsync cc) >>= \a -> when (isNothing a) retry
|
2021-08-05 20:51:48 +01:00
|
|
|
termQ <- newTQueueIO
|
|
|
|
termAsync <- async $ readTerminalOutput t termQ
|
2025-02-15 16:18:34 +00:00
|
|
|
pure TestCC {chatController = cc, virtualTerminal = t, chatAsync, termAsync, termQ, printOutput}
|
2021-08-05 20:51:48 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
stopTestChat :: TestParams -> TestCC -> IO ()
|
|
|
|
stopTestChat ps TestCC {chatController = cc@ChatController {smpAgent, chatStore}, chatAsync, termAsync} = do
|
2023-09-29 11:14:10 +01:00
|
|
|
stopChatController cc
|
2022-04-25 16:30:21 +01:00
|
|
|
uninterruptibleCancel termAsync
|
|
|
|
uninterruptibleCancel chatAsync
|
2024-03-21 19:00:19 +00:00
|
|
|
liftIO $ disposeAgentClient smpAgent
|
2025-01-24 09:44:53 +00:00
|
|
|
#if !defined(dbPostgres)
|
2025-01-24 17:49:31 +04:00
|
|
|
chatStats <- withConnection chatStore $ readTVarIO . DB.slow
|
|
|
|
atomically $ modifyTVar' (chatQueryStats ps) $ M.unionWith combineStats chatStats
|
|
|
|
agentStats <- withConnection (agentClientStore smpAgent) $ readTVarIO . DB.slow
|
|
|
|
atomically $ modifyTVar' (agentQueryStats ps) $ M.unionWith combineStats agentStats
|
2025-01-24 09:44:53 +00:00
|
|
|
#endif
|
2025-01-20 17:41:48 +04:00
|
|
|
closeDBStore chatStore
|
2023-01-31 11:07:48 +00:00
|
|
|
threadDelay 200000
|
2025-01-24 09:44:53 +00:00
|
|
|
#if !defined(dbPostgres)
|
|
|
|
where
|
|
|
|
combineStats
|
|
|
|
DB.SlowQueryStats {count, timeMax, timeAvg, errs}
|
|
|
|
DB.SlowQueryStats {count = count', timeMax = timeMax', timeAvg = timeAvg', errs = errs'} =
|
|
|
|
DB.SlowQueryStats
|
|
|
|
{ count = count + count',
|
|
|
|
timeMax = max timeMax timeMax',
|
|
|
|
timeAvg = (timeAvg * count + timeAvg' * count') `div` (count + count'),
|
|
|
|
errs = M.unionWith (+) errs errs'
|
|
|
|
}
|
|
|
|
#endif
|
2022-04-25 16:30:21 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withNewTestChat :: HasCallStack => TestParams -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withNewTestChat ps = withNewTestChatCfgOpts ps testCfg testOpts
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withNewTestChatV1 :: HasCallStack => TestParams -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withNewTestChatV1 ps = withNewTestChatCfg ps testCfgV1
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withNewTestChatCfg :: HasCallStack => TestParams -> ChatConfig -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withNewTestChatCfg ps cfg = withNewTestChatCfgOpts ps cfg testOpts
|
2022-06-06 16:23:47 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withNewTestChatOpts :: HasCallStack => TestParams -> ChatOpts -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withNewTestChatOpts ps = withNewTestChatCfgOpts ps testCfg
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withNewTestChatCfgOpts :: HasCallStack => TestParams -> ChatConfig -> ChatOpts -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withNewTestChatCfgOpts ps cfg opts dbPrefix profile runTest =
|
2022-10-14 13:06:33 +01:00
|
|
|
bracket
|
2025-01-24 09:44:53 +00:00
|
|
|
(createTestChat ps cfg opts dbPrefix profile)
|
|
|
|
(stopTestChat ps)
|
2022-10-14 13:06:33 +01:00
|
|
|
(\cc -> runTest cc >>= ((cc <// 100000) $>))
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withTestChatV1 :: HasCallStack => TestParams -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withTestChatV1 ps = withTestChatCfg ps testCfgV1
|
2022-04-25 16:30:21 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withTestChat :: HasCallStack => TestParams -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withTestChat ps = withTestChatCfgOpts ps testCfg testOpts
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withTestChatCfg :: HasCallStack => TestParams -> ChatConfig -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withTestChatCfg ps cfg = withTestChatCfgOpts ps cfg testOpts
|
2022-06-06 16:23:47 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withTestChatOpts :: HasCallStack => TestParams -> ChatOpts -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withTestChatOpts ps = withTestChatCfgOpts ps testCfg
|
2022-06-09 14:52:12 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
withTestChatCfgOpts :: HasCallStack => TestParams -> ChatConfig -> ChatOpts -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
|
|
|
withTestChatCfgOpts ps cfg opts dbPrefix = bracket (startTestChat ps cfg opts dbPrefix) (\cc -> cc <// 100000 >> stopTestChat ps cc)
|
2022-04-25 16:30:21 +01:00
|
|
|
|
2025-02-15 16:18:34 +00:00
|
|
|
-- enable output for specific test.
|
|
|
|
-- usage: withTestOutput $ testChat2 aliceProfile bobProfile $ \alice bob -> do ...
|
|
|
|
withTestOutput :: HasCallStack => (HasCallStack => TestParams -> IO ()) -> TestParams -> IO ()
|
|
|
|
withTestOutput test ps = test ps {printOutput = True}
|
2023-05-24 16:14:41 +04:00
|
|
|
|
2021-08-05 20:51:48 +01:00
|
|
|
readTerminalOutput :: VirtualTerminal -> TQueue String -> IO ()
|
|
|
|
readTerminalOutput t termQ = do
|
|
|
|
let w = virtualWindow t
|
|
|
|
winVar <- atomically $ newTVar . init =<< readTVar w
|
|
|
|
forever . atomically $ do
|
|
|
|
win <- readTVar winVar
|
|
|
|
win' <- init <$> readTVar w
|
|
|
|
if win' == win
|
|
|
|
then retry
|
|
|
|
else do
|
|
|
|
let diff = getDiff win' win
|
|
|
|
forM_ diff $ writeTQueue termQ
|
|
|
|
writeTVar winVar win'
|
|
|
|
where
|
|
|
|
getDiff :: [String] -> [String] -> [String]
|
|
|
|
getDiff win win' = getDiff_ 1 (length win) win win'
|
|
|
|
getDiff_ :: Int -> Int -> [String] -> [String] -> [String]
|
|
|
|
getDiff_ n len win' win =
|
|
|
|
let diff = drop (len - n) win'
|
|
|
|
in if drop n win <> diff == win'
|
|
|
|
then map (dropWhileEnd (== ' ')) diff
|
|
|
|
else getDiff_ (n + 1) len win' win
|
2021-07-07 22:46:38 +01:00
|
|
|
|
2022-02-06 16:18:01 +00:00
|
|
|
withTmpFiles :: IO () -> IO ()
|
|
|
|
withTmpFiles =
|
2021-07-24 10:26:28 +01:00
|
|
|
bracket_
|
|
|
|
(createDirectoryIfMissing False "tests/tmp")
|
2023-01-31 11:07:48 +00:00
|
|
|
(removeDirectoryRecursive "tests/tmp")
|
2022-02-06 16:18:01 +00:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatN :: HasCallStack => ChatConfig -> ChatOpts -> [Profile] -> (HasCallStack => [TestCC] -> IO ()) -> TestParams -> IO ()
|
2025-02-25 09:24:30 +00:00
|
|
|
testChatN cfg opts ps test params =
|
|
|
|
bracket (getTestCCs (zip ps [1 ..]) []) entTests test
|
2021-07-24 10:26:28 +01:00
|
|
|
where
|
2022-04-25 16:30:21 +01:00
|
|
|
getTestCCs :: [(Profile, Int)] -> [TestCC] -> IO [TestCC]
|
2021-07-24 10:26:28 +01:00
|
|
|
getTestCCs [] tcs = pure tcs
|
2025-01-24 09:44:53 +00:00
|
|
|
getTestCCs ((p, db) : envs') tcs = (:) <$> createTestChat params cfg opts (show db) p <*> getTestCCs envs' tcs
|
2025-02-25 09:24:30 +00:00
|
|
|
entTests tcs = do
|
|
|
|
concurrentlyN_ $ map (<// 100000) tcs
|
|
|
|
concurrentlyN_ $ map (stopTestChat params) tcs
|
2021-07-24 10:26:28 +01:00
|
|
|
|
2023-01-31 11:07:48 +00:00
|
|
|
(<//) :: HasCallStack => TestCC -> Int -> Expectation
|
2022-02-02 23:50:43 +04:00
|
|
|
(<//) cc t = timeout t (getTermLine cc) `shouldReturn` Nothing
|
|
|
|
|
2023-01-31 11:07:48 +00:00
|
|
|
getTermLine :: HasCallStack => TestCC -> IO String
|
2025-02-15 16:18:34 +00:00
|
|
|
getTermLine cc@TestCC {printOutput} =
|
2022-12-03 18:06:21 +00:00
|
|
|
5000000 `timeout` atomically (readTQueue $ termQ cc) >>= \case
|
|
|
|
Just s -> do
|
2023-05-24 16:14:41 +04:00
|
|
|
-- remove condition to always echo virtual terminal
|
2023-12-11 15:50:32 +02:00
|
|
|
-- when True $ do
|
2025-02-15 16:18:34 +00:00
|
|
|
when printOutput $ do
|
2023-05-24 16:14:41 +04:00
|
|
|
name <- userName cc
|
|
|
|
putStrLn $ name <> ": " <> s
|
2022-12-03 18:06:21 +00:00
|
|
|
pure s
|
|
|
|
_ -> error "no output for 5 seconds"
|
2022-03-10 15:45:40 +04:00
|
|
|
|
2022-03-13 19:34:03 +00:00
|
|
|
userName :: TestCC -> IO [Char]
|
2024-03-05 20:27:00 +04:00
|
|
|
userName (TestCC ChatController {currentUser} _ _ _ _ _) =
|
|
|
|
maybe "no current user" (\User {localDisplayName} -> T.unpack localDisplayName) <$> readTVarIO currentUser
|
2022-03-13 19:34:03 +00:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChat :: HasCallStack => Profile -> (HasCallStack => TestCC -> IO ()) -> TestParams -> IO ()
|
2024-11-22 10:38:00 +00:00
|
|
|
testChat = testChatCfgOpts testCfg testOpts
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfgOpts :: HasCallStack => ChatConfig -> ChatOpts -> Profile -> (HasCallStack => TestCC -> IO ()) -> TestParams -> IO ()
|
2024-11-22 10:38:00 +00:00
|
|
|
testChatCfgOpts cfg opts p test = testChatN cfg opts [p] test_
|
|
|
|
where
|
|
|
|
test_ :: HasCallStack => [TestCC] -> IO ()
|
|
|
|
test_ [tc] = test tc
|
|
|
|
test_ _ = error "expected 1 chat client"
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChat2 :: HasCallStack => Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChat2 = testChatCfgOpts2 testCfg testOpts
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfg2 :: HasCallStack => ChatConfig -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChatCfg2 cfg = testChatCfgOpts2 cfg testOpts
|
2022-06-06 16:23:47 +01:00
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatOpts2 :: HasCallStack => ChatOpts -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChatOpts2 = testChatCfgOpts2 testCfg
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfgOpts2 :: HasCallStack => ChatConfig -> ChatOpts -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChatCfgOpts2 cfg opts p1 p2 test = testChatN cfg opts [p1, p2] test_
|
2021-07-24 10:26:28 +01:00
|
|
|
where
|
2023-08-21 21:45:16 +01:00
|
|
|
test_ :: HasCallStack => [TestCC] -> IO ()
|
2021-07-24 10:26:28 +01:00
|
|
|
test_ [tc1, tc2] = test tc1 tc2
|
|
|
|
test_ _ = error "expected 2 chat clients"
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChat3 :: HasCallStack => Profile -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChat3 = testChatCfgOpts3 testCfg testOpts
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfg3 :: HasCallStack => ChatConfig -> Profile -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChatCfg3 cfg = testChatCfgOpts3 cfg testOpts
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfgOpts3 :: HasCallStack => ChatConfig -> ChatOpts -> Profile -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2022-06-09 14:52:12 +01:00
|
|
|
testChatCfgOpts3 cfg opts p1 p2 p3 test = testChatN cfg opts [p1, p2, p3] test_
|
2021-07-24 10:26:28 +01:00
|
|
|
where
|
2023-08-21 21:45:16 +01:00
|
|
|
test_ :: HasCallStack => [TestCC] -> IO ()
|
2021-07-24 10:26:28 +01:00
|
|
|
test_ [tc1, tc2, tc3] = test tc1 tc2 tc3
|
|
|
|
test_ _ = error "expected 3 chat clients"
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChat4 :: HasCallStack => Profile -> Profile -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2023-09-05 20:15:50 +04:00
|
|
|
testChat4 = testChatCfg4 testCfg
|
|
|
|
|
2025-01-24 09:44:53 +00:00
|
|
|
testChatCfg4 :: HasCallStack => ChatConfig -> Profile -> Profile -> Profile -> Profile -> (HasCallStack => TestCC -> TestCC -> TestCC -> TestCC -> IO ()) -> TestParams -> IO ()
|
2023-09-05 20:15:50 +04:00
|
|
|
testChatCfg4 cfg p1 p2 p3 p4 test = testChatN cfg testOpts [p1, p2, p3, p4] test_
|
2021-07-24 10:26:28 +01:00
|
|
|
where
|
2023-08-21 21:45:16 +01:00
|
|
|
test_ :: HasCallStack => [TestCC] -> IO ()
|
2021-07-24 10:26:28 +01:00
|
|
|
test_ [tc1, tc2, tc3, tc4] = test tc1 tc2 tc3 tc4
|
|
|
|
test_ _ = error "expected 4 chat clients"
|
|
|
|
|
|
|
|
concurrentlyN_ :: [IO a] -> IO ()
|
|
|
|
concurrentlyN_ = mapConcurrently_ id
|
2021-08-05 20:51:48 +01:00
|
|
|
|
2024-05-28 16:42:07 +04:00
|
|
|
smpServerCfg :: ServerConfig
|
|
|
|
smpServerCfg =
|
2021-08-05 20:51:48 +01:00
|
|
|
ServerConfig
|
2024-09-30 14:53:36 +04:00
|
|
|
{ transports = [(serverPort, transport @TLS, False)],
|
2021-08-05 20:51:48 +01:00
|
|
|
tbqSize = 1,
|
2024-11-02 19:51:11 +02:00
|
|
|
msgStoreType = AMSType SMSMemory,
|
2024-11-04 13:28:57 +00:00
|
|
|
msgQueueQuota = 16,
|
|
|
|
maxJournalMsgCount = 24,
|
|
|
|
maxJournalStateLines = 4,
|
2021-08-05 20:51:48 +01:00
|
|
|
queueIdBytes = 12,
|
|
|
|
msgIdBytes = 6,
|
2022-04-21 20:04:22 +01:00
|
|
|
storeLogFile = Nothing,
|
2022-06-16 20:00:51 +01:00
|
|
|
storeMsgsFile = Nothing,
|
2024-09-30 14:53:36 +04:00
|
|
|
storeNtfsFile = Nothing,
|
2022-04-21 20:04:22 +01:00
|
|
|
allowNewQueues = True,
|
2022-12-02 15:01:26 +00:00
|
|
|
-- server password is disabled as otherwise v1 tests fail
|
2022-11-14 08:04:11 +00:00
|
|
|
newQueueBasicAuth = Nothing, -- Just "server_password",
|
2024-03-28 15:09:04 +02:00
|
|
|
controlPortUserAuth = Nothing,
|
|
|
|
controlPortAdminAuth = Nothing,
|
2022-04-30 12:47:50 +01:00
|
|
|
messageExpiration = Just defaultMessageExpiration,
|
2024-11-17 10:25:03 +00:00
|
|
|
expireMessagesOnStart = False,
|
|
|
|
idleQueueInterval = defaultIdleQueueInterval,
|
2024-09-30 14:53:36 +04:00
|
|
|
notificationExpiration = defaultNtfExpiration,
|
2022-04-30 12:47:50 +01:00
|
|
|
inactiveClientExpiration = Just defaultInactiveClientExpiration,
|
2024-09-30 14:53:36 +04:00
|
|
|
smpCredentials =
|
|
|
|
ServerCredentials
|
|
|
|
{ caCertificateFile = Just "tests/fixtures/tls/ca.crt",
|
|
|
|
privateKeyFile = "tests/fixtures/tls/server.key",
|
|
|
|
certificateFile = "tests/fixtures/tls/server.crt"
|
|
|
|
},
|
|
|
|
httpCredentials = Nothing,
|
2023-01-31 11:07:48 +00:00
|
|
|
logStatsInterval = Nothing,
|
2022-06-09 14:52:12 +01:00
|
|
|
logStatsStartTime = 0,
|
2022-07-17 15:51:17 +01:00
|
|
|
serverStatsLogFile = "tests/smp-server-stats.daily.log",
|
|
|
|
serverStatsBackupFile = Nothing,
|
2024-12-20 17:13:31 +00:00
|
|
|
prometheusInterval = Nothing,
|
|
|
|
prometheusMetricsFile = "tests/smp-server-metrics.txt",
|
2024-08-30 13:39:35 +01:00
|
|
|
pendingENDInterval = 500000,
|
2024-09-30 14:53:36 +04:00
|
|
|
ntfDeliveryInterval = 200000,
|
2024-02-17 16:29:45 +00:00
|
|
|
smpServerVRange = supportedServerSMPRelayVRange,
|
2024-09-30 14:53:36 +04:00
|
|
|
transportConfig = defaultTransportServerConfig,
|
2023-12-20 06:38:39 +00:00
|
|
|
smpHandshakeTimeout = 1000000,
|
2024-05-15 15:30:05 +04:00
|
|
|
controlPort = Nothing,
|
|
|
|
smpAgentCfg = defaultSMPClientAgentConfig,
|
2024-07-04 07:58:13 +01:00
|
|
|
allowSMPProxy = True,
|
2024-05-30 14:24:33 +04:00
|
|
|
serverClientConcurrency = 16,
|
2025-02-23 22:21:10 +00:00
|
|
|
information = Nothing,
|
|
|
|
startOptions = StartOptions False False
|
2021-08-05 20:51:48 +01:00
|
|
|
}
|
|
|
|
|
2023-01-31 11:07:48 +00:00
|
|
|
withSmpServer :: IO () -> IO ()
|
2024-05-28 16:42:07 +04:00
|
|
|
withSmpServer = withSmpServer' smpServerCfg
|
|
|
|
|
2024-10-11 18:37:38 +04:00
|
|
|
withSmpServer' :: ServerConfig -> IO a -> IO a
|
2024-09-30 14:53:36 +04:00
|
|
|
withSmpServer' cfg = serverBracket (\started -> runSMPServerBlocking started cfg Nothing)
|
2021-08-05 20:51:48 +01:00
|
|
|
|
2023-03-16 14:12:19 +04:00
|
|
|
xftpTestPort :: ServiceName
|
|
|
|
xftpTestPort = "7002"
|
|
|
|
|
|
|
|
xftpServerFiles :: FilePath
|
|
|
|
xftpServerFiles = "tests/tmp/xftp-server-files"
|
|
|
|
|
|
|
|
xftpServerConfig :: XFTPServerConfig
|
|
|
|
xftpServerConfig =
|
|
|
|
XFTPServerConfig
|
|
|
|
{ xftpPort = xftpTestPort,
|
|
|
|
fileIdSize = 16,
|
2023-03-22 18:48:38 +04:00
|
|
|
storeLogFile = Just "tests/tmp/xftp-server-store.log",
|
2023-03-16 14:12:19 +04:00
|
|
|
filesPath = xftpServerFiles,
|
|
|
|
fileSizeQuota = Nothing,
|
2024-02-17 16:29:45 +00:00
|
|
|
allowedChunkSizes = [kb 64, kb 128, kb 256, mb 1, mb 4],
|
2023-03-16 14:12:19 +04:00
|
|
|
allowNewFiles = True,
|
|
|
|
newFileBasicAuth = Nothing,
|
2024-03-28 15:09:04 +02:00
|
|
|
controlPortUserAuth = Nothing,
|
|
|
|
controlPortAdminAuth = Nothing,
|
2023-03-16 14:12:19 +04:00
|
|
|
fileExpiration = Just defaultFileExpiration,
|
2024-03-19 15:05:45 +00:00
|
|
|
fileTimeout = 10000000,
|
2023-12-27 20:57:05 +00:00
|
|
|
inactiveClientExpiration = Just defaultInactiveClientExpiration,
|
2024-09-30 14:53:36 +04:00
|
|
|
xftpCredentials =
|
|
|
|
ServerCredentials
|
|
|
|
{ caCertificateFile = Just "tests/fixtures/tls/ca.crt",
|
|
|
|
privateKeyFile = "tests/fixtures/tls/server.key",
|
|
|
|
certificateFile = "tests/fixtures/tls/server.crt"
|
|
|
|
},
|
2024-05-15 15:30:05 +04:00
|
|
|
xftpServerVRange = supportedFileServerVRange,
|
2023-03-16 14:12:19 +04:00
|
|
|
logStatsInterval = Nothing,
|
|
|
|
logStatsStartTime = 0,
|
|
|
|
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
|
|
|
|
serverStatsBackupFile = Nothing,
|
2024-01-05 18:51:18 +00:00
|
|
|
controlPort = Nothing,
|
2024-09-30 14:53:36 +04:00
|
|
|
transportConfig = defaultTransportServerConfig,
|
2024-05-31 23:41:20 +01:00
|
|
|
responseDelay = 0
|
2023-03-16 14:12:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
withXFTPServer :: IO () -> IO ()
|
2023-04-18 12:48:36 +04:00
|
|
|
withXFTPServer = withXFTPServer' xftpServerConfig
|
|
|
|
|
|
|
|
withXFTPServer' :: XFTPServerConfig -> IO () -> IO ()
|
|
|
|
withXFTPServer' cfg =
|
2023-03-16 14:12:19 +04:00
|
|
|
serverBracket
|
|
|
|
( \started -> do
|
|
|
|
createDirectoryIfMissing False xftpServerFiles
|
2024-09-30 14:53:36 +04:00
|
|
|
runXFTPServerBlocking started cfg Nothing
|
2023-03-16 14:12:19 +04:00
|
|
|
)
|
|
|
|
|
2024-10-11 18:37:38 +04:00
|
|
|
serverBracket :: (TMVar Bool -> IO ()) -> IO a -> IO a
|
2023-01-31 11:07:48 +00:00
|
|
|
serverBracket server f = do
|
2021-08-05 20:51:48 +01:00
|
|
|
started <- newEmptyTMVarIO
|
|
|
|
bracket
|
2023-01-31 11:07:48 +00:00
|
|
|
(forkIOWithUnmask ($ server started))
|
2024-11-17 10:25:03 +00:00
|
|
|
(\t -> killThread t >> waitFor started "stop" >> threadDelay 100000)
|
2023-01-31 11:07:48 +00:00
|
|
|
(\_ -> waitFor started "start" >> f)
|
2021-08-05 20:51:48 +01:00
|
|
|
where
|
|
|
|
waitFor started s =
|
|
|
|
5000000 `timeout` atomically (takeTMVar started) >>= \case
|
|
|
|
Nothing -> error $ "server did not " <> s
|
|
|
|
_ -> pure ()
|