mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-03-14 09:45:42 +00:00
core: split tests (#1870)
This commit is contained in:
parent
b206868730
commit
4a58ca60ac
8 changed files with 6093 additions and 6013 deletions
|
@ -289,6 +289,11 @@ test-suite simplex-chat-test
|
|||
other-modules:
|
||||
ChatClient
|
||||
ChatTests
|
||||
ChatTests.Direct
|
||||
ChatTests.Files
|
||||
ChatTests.Groups
|
||||
ChatTests.Profiles
|
||||
ChatTests.Utils
|
||||
MarkdownTests
|
||||
MobileTests
|
||||
ProtocolTests
|
||||
|
|
6020
tests/ChatTests.hs
6020
tests/ChatTests.hs
File diff suppressed because it is too large
Load diff
1594
tests/ChatTests/Direct.hs
Normal file
1594
tests/ChatTests/Direct.hs
Normal file
File diff suppressed because it is too large
Load diff
934
tests/ChatTests/Files.hs
Normal file
934
tests/ChatTests/Files.hs
Normal file
|
@ -0,0 +1,934 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE PostfixOperators #-}
|
||||
|
||||
module ChatTests.Files where
|
||||
|
||||
import ChatClient
|
||||
import ChatTests.Utils
|
||||
import Control.Concurrent (threadDelay)
|
||||
import Control.Concurrent.Async (concurrently_)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Simplex.Chat.Controller (ChatConfig (..), InlineFilesConfig (..), defaultInlineFilesConfig)
|
||||
import Simplex.Chat.Options (ChatOpts (..))
|
||||
import Simplex.Messaging.Util (unlessM)
|
||||
import System.Directory (copyFile, doesFileExist)
|
||||
import System.FilePath ((</>))
|
||||
import Test.Hspec
|
||||
|
||||
chatFileTests :: SpecWith FilePath
|
||||
chatFileTests = do
|
||||
describe "sending and receiving files" $ do
|
||||
describe "send and receive file" $ fileTestMatrix2 runTestFileTransfer
|
||||
it "send and receive file inline (without accepting)" testInlineFileTransfer
|
||||
it "accept inline file transfer, sender cancels during transfer" testAcceptInlineFileSndCancelDuringTransfer
|
||||
it "send and receive small file inline (default config)" testSmallInlineFileTransfer
|
||||
it "small file sent without acceptance is ignored in terminal by default" testSmallInlineFileIgnored
|
||||
it "receive file inline with inline=on option" testReceiveInline
|
||||
describe "send and receive a small file" $ fileTestMatrix2 runTestSmallFileTransfer
|
||||
describe "sender cancelled file transfer before transfer" $ fileTestMatrix2 runTestFileSndCancelBeforeTransfer
|
||||
it "sender cancelled file transfer during transfer" testFileSndCancelDuringTransfer
|
||||
it "recipient cancelled file transfer" testFileRcvCancel
|
||||
describe "send and receive file to group" $ fileTestMatrix3 runTestGroupFileTransfer
|
||||
it "send and receive file inline to group (without accepting)" testInlineGroupFileTransfer
|
||||
it "send and receive small file inline to group (default config)" testSmallInlineGroupFileTransfer
|
||||
it "small file sent without acceptance is ignored in terminal by default" testSmallInlineGroupFileIgnored
|
||||
describe "sender cancelled group file transfer before transfer" $ fileTestMatrix3 runTestGroupFileSndCancelBeforeTransfer
|
||||
describe "messages with files" $ do
|
||||
describe "send and receive message with file" $ fileTestMatrix2 runTestMessageWithFile
|
||||
it "send and receive image" testSendImage
|
||||
it "files folder: send and receive image" testFilesFoldersSendImage
|
||||
it "files folder: sender deleted file during transfer" testFilesFoldersImageSndDelete
|
||||
it "files folder: recipient deleted file during transfer" testFilesFoldersImageRcvDelete
|
||||
it "send and receive image with text and quote" testSendImageWithTextAndQuote
|
||||
describe "send and receive image to group" testGroupSendImage
|
||||
it "send and receive image with text and quote to group" testGroupSendImageWithTextAndQuote
|
||||
describe "async sending and receiving files" $ do
|
||||
it "send and receive file, sender restarts" testAsyncFileTransferSenderRestarts
|
||||
it "send and receive file, receiver restarts" testAsyncFileTransferReceiverRestarts
|
||||
xdescribe "send and receive file, fully asynchronous" $ do
|
||||
it "v2" testAsyncFileTransfer
|
||||
it "v1" testAsyncFileTransferV1
|
||||
xit "send and receive file to group, fully asynchronous" testAsyncGroupFileTransfer
|
||||
|
||||
runTestFileTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
runTestFileTransfer alice bob = do
|
||||
connectUsers alice bob
|
||||
startFileTransfer' alice bob "test.pdf" "266.0 KiB / 272376 bytes"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob #> "@alice receiving here..."
|
||||
bob <## "completed receiving file 1 (test.pdf) from alice",
|
||||
alice
|
||||
<### [ WithTime "bob> receiving here...",
|
||||
"completed sending file 1 (test.pdf) to bob"
|
||||
]
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/test.pdf"
|
||||
dest <- B.readFile "./tests/tmp/test.pdf"
|
||||
dest `shouldBe` src
|
||||
|
||||
testInlineFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testInlineFileTransfer =
|
||||
testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do
|
||||
connectUsers alice bob
|
||||
bob ##> "/_files_folder ./tests/tmp/"
|
||||
bob <## "ok"
|
||||
alice ##> "/_send @2 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/test.jpg\"}"
|
||||
alice <# "@bob voice message (00:10)"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> voice message (00:10)"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
-- below is not shown in "sent" mode
|
||||
-- bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
concurrently_
|
||||
(alice <## "completed sending file 1 (test.jpg) to bob")
|
||||
(bob <## "completed receiving file 1 (test.jpg) from alice")
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
where
|
||||
cfg = testCfg {inlineFiles = defaultInlineFilesConfig {offerChunks = 100, sendChunks = 100, receiveChunks = 100}}
|
||||
|
||||
testAcceptInlineFileSndCancelDuringTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testAcceptInlineFileSndCancelDuringTransfer =
|
||||
testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do
|
||||
connectUsers alice bob
|
||||
bob ##> "/_files_folder ./tests/tmp/"
|
||||
bob <## "ok"
|
||||
alice #> "/f @bob ./tests/fixtures/test_1MB.pdf"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 inline=on"
|
||||
bob <## "saving file 1 from alice to test_1MB.pdf"
|
||||
alice <## "started sending file 1 (test_1MB.pdf) to bob"
|
||||
bob <## "started receiving file 1 (test_1MB.pdf) from alice"
|
||||
alice ##> "/fc 1" -- test that inline file cancel doesn't delete contact connection
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <##. "cancelled sending file 1 (test_1MB.pdf)"
|
||||
alice <## "completed sending file 1 (test_1MB.pdf) to bob",
|
||||
do
|
||||
bob <## "completed receiving file 1 (test_1MB.pdf) from alice"
|
||||
bob <## "alice cancelled sending file 1 (test_1MB.pdf)"
|
||||
]
|
||||
alice #> "@bob hi"
|
||||
bob <# "alice> hi"
|
||||
bob #> "@alice hey"
|
||||
alice <# "bob> hey"
|
||||
where
|
||||
cfg = testCfg {inlineFiles = defaultInlineFilesConfig {offerChunks = 100, receiveChunks = 50}}
|
||||
|
||||
testSmallInlineFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testSmallInlineFileTransfer =
|
||||
testChat2 aliceProfile bobProfile $ \alice bob -> do
|
||||
connectUsers alice bob
|
||||
bob ##> "/_files_folder ./tests/tmp/"
|
||||
bob <## "ok"
|
||||
alice ##> "/_send @2 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/logo.jpg\"}"
|
||||
alice <# "@bob voice message (00:10)"
|
||||
alice <# "/f @bob ./tests/fixtures/logo.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> voice message (00:10)"
|
||||
bob <# "alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
-- below is not shown in "sent" mode
|
||||
-- bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob <## "started receiving file 1 (logo.jpg) from alice"
|
||||
concurrently_
|
||||
(alice <## "completed sending file 1 (logo.jpg) to bob")
|
||||
(bob <## "completed receiving file 1 (logo.jpg) from alice")
|
||||
src <- B.readFile "./tests/fixtures/logo.jpg"
|
||||
dest <- B.readFile "./tests/tmp/logo.jpg"
|
||||
dest `shouldBe` src
|
||||
|
||||
testSmallInlineFileIgnored :: HasCallStack => FilePath -> IO ()
|
||||
testSmallInlineFileIgnored tmp = do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatOpts tmp testOpts {allowInstantFiles = False} "bob" bobProfile $ \bob -> do
|
||||
connectUsers alice bob
|
||||
bob ##> "/_files_folder ./tests/tmp/"
|
||||
bob <## "ok"
|
||||
alice ##> "/_send @2 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/logo.jpg\"}"
|
||||
alice <# "@bob voice message (00:10)"
|
||||
alice <# "/f @bob ./tests/fixtures/logo.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> voice message (00:10)"
|
||||
bob <# "alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob <## "A small file sent without acceptance - you can enable receiving such files with -f option."
|
||||
-- below is not shown in "sent" mode
|
||||
-- bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
alice <## "completed sending file 1 (logo.jpg) to bob"
|
||||
bob ##> "/fr 1"
|
||||
bob <## "file is already being received: logo.jpg"
|
||||
|
||||
testReceiveInline :: HasCallStack => FilePath -> IO ()
|
||||
testReceiveInline =
|
||||
testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do
|
||||
connectUsers alice bob
|
||||
alice #> "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 inline=on ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob"
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
where
|
||||
cfg = testCfg {inlineFiles = defaultInlineFilesConfig {offerChunks = 10, receiveChunks = 5}}
|
||||
|
||||
runTestSmallFileTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
runTestSmallFileTransfer alice bob = do
|
||||
connectUsers alice bob
|
||||
alice #> "/f @bob ./tests/fixtures/test.txt"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.txt (11 bytes / 11 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.txt"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <## "started receiving file 1 (test.txt) from alice"
|
||||
bob <## "completed receiving file 1 (test.txt) from alice",
|
||||
do
|
||||
alice <## "started sending file 1 (test.txt) to bob"
|
||||
alice <## "completed sending file 1 (test.txt) to bob"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/test.txt"
|
||||
dest <- B.readFile "./tests/tmp/test.txt"
|
||||
dest `shouldBe` src
|
||||
|
||||
runTestFileSndCancelBeforeTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
runTestFileSndCancelBeforeTransfer alice bob = do
|
||||
connectUsers alice bob
|
||||
alice #> "/f @bob ./tests/fixtures/test.txt"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.txt (11 bytes / 11 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
alice ##> "/fc 1"
|
||||
concurrentlyN_
|
||||
[ alice <##. "cancelled sending file 1 (test.txt)",
|
||||
bob <## "alice cancelled sending file 1 (test.txt)"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
alice
|
||||
<##.. [ "sending file 1 (test.txt): no file transfers",
|
||||
"sending file 1 (test.txt) cancelled: bob"
|
||||
]
|
||||
alice <## "file transfer cancelled"
|
||||
bob ##> "/fs 1"
|
||||
bob <## "receiving file 1 (test.txt) cancelled"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "file cancelled: test.txt"
|
||||
|
||||
testFileSndCancelDuringTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testFileSndCancelDuringTransfer =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
startFileTransfer' alice bob "test_1MB.pdf" "1017.7 KiB / 1042157 bytes"
|
||||
alice ##> "/fc 1"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "cancelled sending file 1 (test_1MB.pdf) to bob"
|
||||
alice ##> "/fs 1"
|
||||
alice <## "sending file 1 (test_1MB.pdf) cancelled: bob"
|
||||
alice <## "file transfer cancelled",
|
||||
do
|
||||
bob <## "alice cancelled sending file 1 (test_1MB.pdf)"
|
||||
bob ##> "/fs 1"
|
||||
bob <## "receiving file 1 (test_1MB.pdf) cancelled, received part path: ./tests/tmp/test_1MB.pdf"
|
||||
]
|
||||
checkPartialTransfer "test_1MB.pdf"
|
||||
|
||||
testFileRcvCancel :: HasCallStack => FilePath -> IO ()
|
||||
testFileRcvCancel =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
startFileTransfer alice bob
|
||||
bob ##> "/fs 1"
|
||||
getTermLine bob >>= (`shouldStartWith` "receiving file 1 (test.jpg) progress")
|
||||
waitFileExists "./tests/tmp/test.jpg"
|
||||
bob ##> "/fc 1"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <## "cancelled receiving file 1 (test.jpg) from alice"
|
||||
bob ##> "/fs 1"
|
||||
bob <## "receiving file 1 (test.jpg) cancelled, received part path: ./tests/tmp/test.jpg",
|
||||
do
|
||||
alice <## "bob cancelled receiving file 1 (test.jpg)"
|
||||
alice ##> "/fs 1"
|
||||
alice <## "sending file 1 (test.jpg) cancelled: bob"
|
||||
]
|
||||
checkPartialTransfer "test.jpg"
|
||||
|
||||
runTestGroupFileTransfer :: HasCallStack => TestCC -> TestCC -> TestCC -> IO ()
|
||||
runTestGroupFileTransfer alice bob cath = do
|
||||
createGroup3 "team" alice bob cath
|
||||
alice #> "/f #team ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it",
|
||||
do
|
||||
cath <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
getTermLine alice >>= (`shouldStartWith` "sending file 1 (test.jpg): no file transfers")
|
||||
bob ##> "/fr 1 ./tests/tmp/"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob"
|
||||
alice ##> "/fs 1"
|
||||
alice <## "sending file 1 (test.jpg) complete: bob",
|
||||
do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
cath ##> "/fr 1 ./tests/tmp/"
|
||||
cath <## "saving file 1 from alice to ./tests/tmp/test_1.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to cath"
|
||||
alice <## "completed sending file 1 (test.jpg) to cath"
|
||||
alice ##> "/fs 1"
|
||||
getTermLine alice >>= (`shouldStartWith` "sending file 1 (test.jpg) complete"),
|
||||
do
|
||||
cath <## "started receiving file 1 (test.jpg) from alice"
|
||||
cath <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest1 <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest2 <- B.readFile "./tests/tmp/test_1.jpg"
|
||||
dest1 `shouldBe` src
|
||||
dest2 `shouldBe` src
|
||||
|
||||
testInlineGroupFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testInlineGroupFileTransfer =
|
||||
testChatCfg3 cfg aliceProfile bobProfile cathProfile $
|
||||
\alice bob cath -> do
|
||||
createGroup3 "team" alice bob cath
|
||||
bob ##> "/_files_folder ./tests/tmp/bob/"
|
||||
bob <## "ok"
|
||||
cath ##> "/_files_folder ./tests/tmp/cath/"
|
||||
cath <## "ok"
|
||||
alice ##> "/_send #1 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/logo.jpg\"}"
|
||||
alice <# "#team voice message (00:10)"
|
||||
alice <# "/f #team ./tests/fixtures/logo.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice
|
||||
<### [ "completed sending file 1 (logo.jpg) to bob",
|
||||
"completed sending file 1 (logo.jpg) to cath"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
alice <##. "sending file 1 (logo.jpg) complete",
|
||||
do
|
||||
bob <# "#team alice> voice message (00:10)"
|
||||
bob <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
bob <## "started receiving file 1 (logo.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (logo.jpg) from alice",
|
||||
do
|
||||
cath <# "#team alice> voice message (00:10)"
|
||||
cath <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
cath <## "started receiving file 1 (logo.jpg) from alice"
|
||||
cath <## "completed receiving file 1 (logo.jpg) from alice"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/logo.jpg"
|
||||
dest1 <- B.readFile "./tests/tmp/bob/logo.jpg"
|
||||
dest2 <- B.readFile "./tests/tmp/cath/logo.jpg"
|
||||
dest1 `shouldBe` src
|
||||
dest2 `shouldBe` src
|
||||
where
|
||||
cfg = testCfg {inlineFiles = defaultInlineFilesConfig {offerChunks = 100, sendChunks = 100, totalSendChunks = 100, receiveChunks = 100}}
|
||||
|
||||
testSmallInlineGroupFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testSmallInlineGroupFileTransfer =
|
||||
testChatCfg3 testCfg aliceProfile bobProfile cathProfile $
|
||||
\alice bob cath -> do
|
||||
createGroup3 "team" alice bob cath
|
||||
bob ##> "/_files_folder ./tests/tmp/bob/"
|
||||
bob <## "ok"
|
||||
cath ##> "/_files_folder ./tests/tmp/cath/"
|
||||
cath <## "ok"
|
||||
alice ##> "/_send #1 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/logo.jpg\"}"
|
||||
alice <# "#team voice message (00:10)"
|
||||
alice <# "/f #team ./tests/fixtures/logo.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice
|
||||
<### [ "completed sending file 1 (logo.jpg) to bob",
|
||||
"completed sending file 1 (logo.jpg) to cath"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
alice <##. "sending file 1 (logo.jpg) complete",
|
||||
do
|
||||
bob <# "#team alice> voice message (00:10)"
|
||||
bob <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
bob <## "started receiving file 1 (logo.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (logo.jpg) from alice",
|
||||
do
|
||||
cath <# "#team alice> voice message (00:10)"
|
||||
cath <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
cath <## "started receiving file 1 (logo.jpg) from alice"
|
||||
cath <## "completed receiving file 1 (logo.jpg) from alice"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/logo.jpg"
|
||||
dest1 <- B.readFile "./tests/tmp/bob/logo.jpg"
|
||||
dest2 <- B.readFile "./tests/tmp/cath/logo.jpg"
|
||||
dest1 `shouldBe` src
|
||||
dest2 `shouldBe` src
|
||||
|
||||
testSmallInlineGroupFileIgnored :: HasCallStack => FilePath -> IO ()
|
||||
testSmallInlineGroupFileIgnored tmp = do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatOpts tmp testOpts {allowInstantFiles = False} "bob" bobProfile $ \bob -> do
|
||||
withNewTestChatOpts tmp testOpts {allowInstantFiles = False} "cath" cathProfile $ \cath -> do
|
||||
createGroup3 "team" alice bob cath
|
||||
bob ##> "/_files_folder ./tests/tmp/bob/"
|
||||
bob <## "ok"
|
||||
cath ##> "/_files_folder ./tests/tmp/cath/"
|
||||
cath <## "ok"
|
||||
alice ##> "/_send #1 json {\"msgContent\":{\"type\":\"voice\", \"duration\":10, \"text\":\"\"}, \"filePath\":\"./tests/fixtures/logo.jpg\"}"
|
||||
alice <# "#team voice message (00:10)"
|
||||
alice <# "/f #team ./tests/fixtures/logo.jpg"
|
||||
-- below is not shown in "sent" mode
|
||||
-- alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice
|
||||
<### [ "completed sending file 1 (logo.jpg) to bob",
|
||||
"completed sending file 1 (logo.jpg) to cath"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
alice <##. "sending file 1 (logo.jpg) complete",
|
||||
do
|
||||
bob <# "#team alice> voice message (00:10)"
|
||||
bob <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob <## "A small file sent without acceptance - you can enable receiving such files with -f option."
|
||||
bob ##> "/fr 1"
|
||||
bob <## "file is already being received: logo.jpg",
|
||||
do
|
||||
cath <# "#team alice> voice message (00:10)"
|
||||
cath <# "#team alice> sends file logo.jpg (31.3 KiB / 32080 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
cath <## "A small file sent without acceptance - you can enable receiving such files with -f option."
|
||||
cath ##> "/fr 1"
|
||||
cath <## "file is already being received: logo.jpg"
|
||||
]
|
||||
|
||||
runTestGroupFileSndCancelBeforeTransfer :: HasCallStack => TestCC -> TestCC -> TestCC -> IO ()
|
||||
runTestGroupFileSndCancelBeforeTransfer alice bob cath = do
|
||||
createGroup3 "team" alice bob cath
|
||||
alice #> "/f #team ./tests/fixtures/test.txt"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <# "#team alice> sends file test.txt (11 bytes / 11 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it",
|
||||
do
|
||||
cath <# "#team alice> sends file test.txt (11 bytes / 11 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
]
|
||||
alice ##> "/fc 1"
|
||||
concurrentlyN_
|
||||
[ alice <## "cancelled sending file 1 (test.txt)",
|
||||
bob <## "alice cancelled sending file 1 (test.txt)",
|
||||
cath <## "alice cancelled sending file 1 (test.txt)"
|
||||
]
|
||||
alice ##> "/fs 1"
|
||||
alice <## "sending file 1 (test.txt): no file transfers"
|
||||
alice <## "file transfer cancelled"
|
||||
bob ##> "/fs 1"
|
||||
bob <## "receiving file 1 (test.txt) cancelled"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "file cancelled: test.txt"
|
||||
|
||||
runTestMessageWithFile :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
runTestMessageWithFile alice bob = do
|
||||
connectUsers alice bob
|
||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi, sending a file\"}}"
|
||||
alice <# "@bob hi, sending a file"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> hi, sending a file"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "started sending file 1 (test.jpg) to bob")
|
||||
concurrently_
|
||||
(bob <## "completed receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "completed sending file 1 (test.jpg) to bob")
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
alice #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((1, "hi, sending a file"), Just "./tests/fixtures/test.jpg")])
|
||||
bob #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((0, "hi, sending a file"), Just "./tests/tmp/test.jpg")])
|
||||
|
||||
testSendImage :: HasCallStack => FilePath -> IO ()
|
||||
testSendImage =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "started sending file 1 (test.jpg) to bob")
|
||||
concurrently_
|
||||
(bob <## "completed receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "completed sending file 1 (test.jpg) to bob")
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
alice #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((1, ""), Just "./tests/fixtures/test.jpg")])
|
||||
bob #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((0, ""), Just "./tests/tmp/test.jpg")])
|
||||
-- deleting contact without files folder set should not remove file
|
||||
bob ##> "/d alice"
|
||||
bob <## "alice: contact is deleted"
|
||||
fileExists <- doesFileExist "./tests/tmp/test.jpg"
|
||||
fileExists `shouldBe` True
|
||||
|
||||
testFilesFoldersSendImage :: HasCallStack => FilePath -> IO ()
|
||||
testFilesFoldersSendImage =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
||||
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
||||
alice ##> "/_send @2 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
||||
alice <# "/f @bob test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1"
|
||||
bob <## "saving file 1 from alice to test.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "started sending file 1 (test.jpg) to bob")
|
||||
concurrently_
|
||||
(bob <## "completed receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "completed sending file 1 (test.jpg) to bob")
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/app_files/test.jpg"
|
||||
dest `shouldBe` src
|
||||
alice #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((1, ""), Just "test.jpg")])
|
||||
bob #$> ("/_get chat @2 count=100", chatF, chatFeaturesF <> [((0, ""), Just "test.jpg")])
|
||||
-- deleting contact with files folder set should remove file
|
||||
checkActionDeletesFile "./tests/tmp/app_files/test.jpg" $ do
|
||||
bob ##> "/d alice"
|
||||
bob <## "alice: contact is deleted"
|
||||
|
||||
testFilesFoldersImageSndDelete :: HasCallStack => FilePath -> IO ()
|
||||
testFilesFoldersImageSndDelete =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
alice #$> ("/_files_folder ./tests/tmp/alice_app_files", id, "ok")
|
||||
copyFile "./tests/fixtures/test_1MB.pdf" "./tests/tmp/alice_app_files/test_1MB.pdf"
|
||||
bob #$> ("/_files_folder ./tests/tmp/bob_app_files", id, "ok")
|
||||
alice ##> "/_send @2 json {\"filePath\": \"test_1MB.pdf\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
||||
alice <# "/f @bob test_1MB.pdf"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1"
|
||||
bob <## "saving file 1 from alice to test_1MB.pdf"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test_1MB.pdf) from alice")
|
||||
(alice <## "started sending file 1 (test_1MB.pdf) to bob")
|
||||
-- deleting contact should cancel and remove file
|
||||
checkActionDeletesFile "./tests/tmp/alice_app_files/test_1MB.pdf" $ do
|
||||
alice ##> "/d bob"
|
||||
alice <## "bob: contact is deleted"
|
||||
bob ##> "/fs 1"
|
||||
bob <##. "receiving file 1 (test_1MB.pdf) progress"
|
||||
-- deleting contact should remove cancelled file
|
||||
checkActionDeletesFile "./tests/tmp/bob_app_files/test_1MB.pdf" $ do
|
||||
bob ##> "/d alice"
|
||||
bob <## "alice: contact is deleted"
|
||||
|
||||
testFilesFoldersImageRcvDelete :: HasCallStack => FilePath -> IO ()
|
||||
testFilesFoldersImageRcvDelete =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
||||
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
||||
alice ##> "/_send @2 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
||||
alice <# "/f @bob test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1"
|
||||
bob <## "saving file 1 from alice to test.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "started sending file 1 (test.jpg) to bob")
|
||||
-- deleting contact should cancel and remove file
|
||||
waitFileExists "./tests/tmp/app_files/test.jpg"
|
||||
checkActionDeletesFile "./tests/tmp/app_files/test.jpg" $ do
|
||||
bob ##> "/d alice"
|
||||
bob <## "alice: contact is deleted"
|
||||
alice <## "bob cancelled receiving file 1 (test.jpg)"
|
||||
alice ##> "/fs 1"
|
||||
alice <## "sending file 1 (test.jpg) cancelled: bob"
|
||||
|
||||
testSendImageWithTextAndQuote :: HasCallStack => FilePath -> IO ()
|
||||
testSendImageWithTextAndQuote =
|
||||
testChat2 aliceProfile bobProfile $
|
||||
\alice bob -> do
|
||||
connectUsers alice bob
|
||||
bob #> "@alice hi alice"
|
||||
alice <# "bob> hi alice"
|
||||
alice ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 1 <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
||||
alice <# "@bob > hi alice"
|
||||
alice <## " hey bob"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
bob <# "alice> > hi alice"
|
||||
bob <## " hey bob"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "started sending file 1 (test.jpg) to bob")
|
||||
concurrently_
|
||||
(bob <## "completed receiving file 1 (test.jpg) from alice")
|
||||
(alice <## "completed sending file 1 (test.jpg) to bob")
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
B.readFile "./tests/tmp/test.jpg" `shouldReturn` src
|
||||
alice #$> ("/_get chat @2 count=100", chat'', chatFeatures'' <> [((0, "hi alice"), Nothing, Nothing), ((1, "hey bob"), Just (0, "hi alice"), Just "./tests/fixtures/test.jpg")])
|
||||
alice @@@ [("@bob", "hey bob")]
|
||||
bob #$> ("/_get chat @2 count=100", chat'', chatFeatures'' <> [((1, "hi alice"), Nothing, Nothing), ((0, "hey bob"), Just (1, "hi alice"), Just "./tests/tmp/test.jpg")])
|
||||
bob @@@ [("@alice", "hey bob")]
|
||||
-- quoting (file + text) with file uses quoted text
|
||||
bob ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.pdf\", \"quotedItemId\": " <> itemId 2 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"file\"}}")
|
||||
bob <# "@alice > hey bob"
|
||||
bob <## " test.pdf"
|
||||
bob <# "/f @alice ./tests/fixtures/test.pdf"
|
||||
bob <## "use /fc 2 to cancel sending"
|
||||
alice <# "bob> > hey bob"
|
||||
alice <## " test.pdf"
|
||||
alice <# "bob> sends file test.pdf (266.0 KiB / 272376 bytes)"
|
||||
alice <## "use /fr 2 [<dir>/ | <path>] to receive it"
|
||||
alice ##> "/fr 2 ./tests/tmp"
|
||||
alice <## "saving file 2 from bob to ./tests/tmp/test.pdf"
|
||||
concurrently_
|
||||
(alice <## "started receiving file 2 (test.pdf) from bob")
|
||||
(bob <## "started sending file 2 (test.pdf) to alice")
|
||||
concurrently_
|
||||
(alice <## "completed receiving file 2 (test.pdf) from bob")
|
||||
(bob <## "completed sending file 2 (test.pdf) to alice")
|
||||
txtSrc <- B.readFile "./tests/fixtures/test.pdf"
|
||||
B.readFile "./tests/tmp/test.pdf" `shouldReturn` txtSrc
|
||||
-- quoting (file without text) with file uses file name
|
||||
alice ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 3 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
||||
alice <# "@bob > test.pdf"
|
||||
alice <## " test.jpg"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 3 to cancel sending"
|
||||
bob <# "alice> > test.pdf"
|
||||
bob <## " test.jpg"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 3 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 3 ./tests/tmp"
|
||||
bob <## "saving file 3 from alice to ./tests/tmp/test_1.jpg"
|
||||
concurrently_
|
||||
(bob <## "started receiving file 3 (test.jpg) from alice")
|
||||
(alice <## "started sending file 3 (test.jpg) to bob")
|
||||
concurrently_
|
||||
(bob <## "completed receiving file 3 (test.jpg) from alice")
|
||||
(alice <## "completed sending file 3 (test.jpg) to bob")
|
||||
B.readFile "./tests/tmp/test_1.jpg" `shouldReturn` src
|
||||
|
||||
testGroupSendImage :: SpecWith FilePath
|
||||
testGroupSendImage = versionTestMatrix3 runTestGroupSendImage
|
||||
where
|
||||
runTestGroupSendImage :: HasCallStack => TestCC -> TestCC -> TestCC -> IO ()
|
||||
runTestGroupSendImage alice bob cath = do
|
||||
createGroup3 "team" alice bob cath
|
||||
threadDelay 1000000
|
||||
alice ##> "/_send #1 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
||||
alice <# "/f #team ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it",
|
||||
do
|
||||
cath <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
]
|
||||
bob ##> "/fr 1 ./tests/tmp/"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob",
|
||||
do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
cath ##> "/fr 1 ./tests/tmp/"
|
||||
cath <## "saving file 1 from alice to ./tests/tmp/test_1.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to cath"
|
||||
alice <## "completed sending file 1 (test.jpg) to cath",
|
||||
do
|
||||
cath <## "started receiving file 1 (test.jpg) from alice"
|
||||
cath <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
dest2 <- B.readFile "./tests/tmp/test_1.jpg"
|
||||
dest2 `shouldBe` src
|
||||
alice #$> ("/_get chat #1 count=1", chatF, [((1, ""), Just "./tests/fixtures/test.jpg")])
|
||||
bob #$> ("/_get chat #1 count=1", chatF, [((0, ""), Just "./tests/tmp/test.jpg")])
|
||||
cath #$> ("/_get chat #1 count=1", chatF, [((0, ""), Just "./tests/tmp/test_1.jpg")])
|
||||
|
||||
testGroupSendImageWithTextAndQuote :: HasCallStack => FilePath -> IO ()
|
||||
testGroupSendImageWithTextAndQuote =
|
||||
testChat3 aliceProfile bobProfile cathProfile $
|
||||
\alice bob cath -> do
|
||||
createGroup3 "team" alice bob cath
|
||||
threadDelay 1000000
|
||||
bob #> "#team hi team"
|
||||
concurrently_
|
||||
(alice <# "#team bob> hi team")
|
||||
(cath <# "#team bob> hi team")
|
||||
threadDelay 1000000
|
||||
msgItemId <- lastItemId alice
|
||||
alice ##> ("/_send #1 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> msgItemId <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
||||
alice <# "#team > bob hi team"
|
||||
alice <## " hey bob"
|
||||
alice <# "/f #team ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <# "#team alice> > bob hi team"
|
||||
bob <## " hey bob"
|
||||
bob <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it",
|
||||
do
|
||||
cath <# "#team alice> > bob hi team"
|
||||
cath <## " hey bob"
|
||||
cath <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
]
|
||||
bob ##> "/fr 1 ./tests/tmp/"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob",
|
||||
do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
cath ##> "/fr 1 ./tests/tmp/"
|
||||
cath <## "saving file 1 from alice to ./tests/tmp/test_1.jpg"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "started sending file 1 (test.jpg) to cath"
|
||||
alice <## "completed sending file 1 (test.jpg) to cath",
|
||||
do
|
||||
cath <## "started receiving file 1 (test.jpg) from alice"
|
||||
cath <## "completed receiving file 1 (test.jpg) from alice"
|
||||
]
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
dest2 <- B.readFile "./tests/tmp/test_1.jpg"
|
||||
dest2 `shouldBe` src
|
||||
alice #$> ("/_get chat #1 count=2", chat'', [((0, "hi team"), Nothing, Nothing), ((1, "hey bob"), Just (0, "hi team"), Just "./tests/fixtures/test.jpg")])
|
||||
alice @@@ [("#team", "hey bob"), ("@bob", "sent invitation to join group team as admin"), ("@cath", "sent invitation to join group team as admin")]
|
||||
bob #$> ("/_get chat #1 count=2", chat'', [((1, "hi team"), Nothing, Nothing), ((0, "hey bob"), Just (1, "hi team"), Just "./tests/tmp/test.jpg")])
|
||||
bob @@@ [("#team", "hey bob"), ("@alice", "received invitation to join group team as admin")]
|
||||
cath #$> ("/_get chat #1 count=2", chat'', [((0, "hi team"), Nothing, Nothing), ((0, "hey bob"), Just (0, "hi team"), Just "./tests/tmp/test_1.jpg")])
|
||||
cath @@@ [("#team", "hey bob"), ("@alice", "received invitation to join group team as admin")]
|
||||
|
||||
testAsyncFileTransferSenderRestarts :: HasCallStack => FilePath -> IO ()
|
||||
testAsyncFileTransferSenderRestarts tmp = do
|
||||
withNewTestChat tmp "bob" bobProfile $ \bob -> do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||
connectUsers alice bob
|
||||
startFileTransfer' alice bob "test_1MB.pdf" "1017.7 KiB / 1042157 bytes"
|
||||
threadDelay 100000
|
||||
withTestChatContactConnected tmp "alice" $ \alice -> do
|
||||
alice <## "completed sending file 1 (test_1MB.pdf) to bob"
|
||||
bob <## "completed receiving file 1 (test_1MB.pdf) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test_1MB.pdf"
|
||||
dest <- B.readFile "./tests/tmp/test_1MB.pdf"
|
||||
dest `shouldBe` src
|
||||
|
||||
testAsyncFileTransferReceiverRestarts :: HasCallStack => FilePath -> IO ()
|
||||
testAsyncFileTransferReceiverRestarts tmp = do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||
withNewTestChat tmp "bob" bobProfile $ \bob -> do
|
||||
connectUsers alice bob
|
||||
startFileTransfer' alice bob "test_1MB.pdf" "1017.7 KiB / 1042157 bytes"
|
||||
threadDelay 100000
|
||||
withTestChatContactConnected tmp "bob" $ \bob -> do
|
||||
alice <## "completed sending file 1 (test_1MB.pdf) to bob"
|
||||
bob <## "completed receiving file 1 (test_1MB.pdf) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test_1MB.pdf"
|
||||
dest <- B.readFile "./tests/tmp/test_1MB.pdf"
|
||||
dest `shouldBe` src
|
||||
|
||||
testAsyncFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testAsyncFileTransfer tmp = do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice ->
|
||||
withNewTestChat tmp "bob" bobProfile $ \bob ->
|
||||
connectUsers alice bob
|
||||
withTestChatContactConnected tmp "alice" $ \alice -> do
|
||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"type\":\"text\", \"text\": \"hi, sending a file\"}}"
|
||||
alice <# "@bob hi, sending a file"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
withTestChatContactConnected tmp "bob" $ \bob -> do
|
||||
bob <# "alice> hi, sending a file"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
-- withTestChatContactConnected' tmp "alice" -- TODO not needed in v2
|
||||
-- withTestChatContactConnected' tmp "bob" -- TODO not needed in v2
|
||||
withTestChatContactConnected' tmp "alice"
|
||||
withTestChatContactConnected' tmp "bob"
|
||||
withTestChatContactConnected tmp "alice" $ \alice -> do
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob"
|
||||
withTestChatContactConnected tmp "bob" $ \bob -> do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
|
||||
testAsyncFileTransferV1 :: HasCallStack => FilePath -> IO ()
|
||||
testAsyncFileTransferV1 tmp = do
|
||||
withNewTestChatV1 tmp "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatV1 tmp "bob" bobProfile $ \bob ->
|
||||
connectUsers alice bob
|
||||
withTestChatContactConnectedV1 tmp "alice" $ \alice -> do
|
||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"type\":\"text\", \"text\": \"hi, sending a file\"}}"
|
||||
alice <# "@bob hi, sending a file"
|
||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
withTestChatContactConnectedV1 tmp "bob" $ \bob -> do
|
||||
bob <# "alice> hi, sending a file"
|
||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
withTestChatContactConnectedV1' tmp "alice" -- TODO not needed in v2
|
||||
withTestChatContactConnectedV1' tmp "bob" -- TODO not needed in v2
|
||||
withTestChatContactConnectedV1' tmp "alice"
|
||||
withTestChatContactConnectedV1' tmp "bob"
|
||||
withTestChatContactConnectedV1 tmp "alice" $ \alice -> do
|
||||
alice <## "started sending file 1 (test.jpg) to bob"
|
||||
alice <## "completed sending file 1 (test.jpg) to bob"
|
||||
withTestChatContactConnectedV1 tmp "bob" $ \bob -> do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
|
||||
testAsyncGroupFileTransfer :: HasCallStack => FilePath -> IO ()
|
||||
testAsyncGroupFileTransfer tmp = do
|
||||
withNewTestChat tmp "alice" aliceProfile $ \alice ->
|
||||
withNewTestChat tmp "bob" bobProfile $ \bob ->
|
||||
withNewTestChat tmp "cath" cathProfile $ \cath ->
|
||||
createGroup3 "team" alice bob cath
|
||||
withTestChatGroup3Connected tmp "alice" $ \alice -> do
|
||||
alice ##> "/_send #1 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"text\"}}"
|
||||
alice <# "/f #team ./tests/fixtures/test.jpg"
|
||||
alice <## "use /fc 1 to cancel sending"
|
||||
withTestChatGroup3Connected tmp "bob" $ \bob -> do
|
||||
bob <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
bob ##> "/fr 1 ./tests/tmp/"
|
||||
bob <## "saving file 1 from alice to ./tests/tmp/test.jpg"
|
||||
withTestChatGroup3Connected tmp "cath" $ \cath -> do
|
||||
cath <# "#team alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
cath ##> "/fr 1 ./tests/tmp/"
|
||||
cath <## "saving file 1 from alice to ./tests/tmp/test_1.jpg"
|
||||
withTestChatGroup3Connected' tmp "alice"
|
||||
withTestChatGroup3Connected' tmp "bob"
|
||||
withTestChatGroup3Connected' tmp "cath"
|
||||
-- withTestChatGroup3Connected' tmp "alice" -- TODO not needed in v2
|
||||
-- withTestChatGroup3Connected' tmp "bob" -- TODO not needed in v2
|
||||
-- withTestChatGroup3Connected' tmp "cath" -- TODO not needed in v2
|
||||
withTestChatGroup3Connected' tmp "alice"
|
||||
withTestChatGroup3Connected tmp "bob" $ \bob -> do
|
||||
bob <## "started receiving file 1 (test.jpg) from alice"
|
||||
withTestChatGroup3Connected tmp "cath" $ \cath -> do
|
||||
cath <## "started receiving file 1 (test.jpg) from alice"
|
||||
withTestChatGroup3Connected tmp "alice" $ \alice -> do
|
||||
alice
|
||||
<### [ "started sending file 1 (test.jpg) to bob",
|
||||
"completed sending file 1 (test.jpg) to bob",
|
||||
"started sending file 1 (test.jpg) to cath",
|
||||
"completed sending file 1 (test.jpg) to cath"
|
||||
]
|
||||
withTestChatGroup3Connected tmp "bob" $ \bob -> do
|
||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||
withTestChatGroup3Connected tmp "cath" $ \cath -> do
|
||||
cath <## "completed receiving file 1 (test.jpg) from alice"
|
||||
src <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dest <- B.readFile "./tests/tmp/test.jpg"
|
||||
dest `shouldBe` src
|
||||
dest2 <- B.readFile "./tests/tmp/test_1.jpg"
|
||||
dest2 `shouldBe` src
|
||||
|
||||
startFileTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
startFileTransfer alice bob =
|
||||
startFileTransfer' alice bob "test.jpg" "136.5 KiB / 139737 bytes"
|
||||
|
||||
startFileTransfer' :: HasCallStack => TestCC -> TestCC -> String -> String -> IO ()
|
||||
startFileTransfer' cc1 cc2 fileName fileSize = startFileTransferWithDest' cc1 cc2 fileName fileSize $ Just "./tests/tmp"
|
||||
|
||||
checkPartialTransfer :: HasCallStack => String -> IO ()
|
||||
checkPartialTransfer fileName = do
|
||||
src <- B.readFile $ "./tests/fixtures/" <> fileName
|
||||
dest <- B.readFile $ "./tests/tmp/" <> fileName
|
||||
B.unpack src `shouldStartWith` B.unpack dest
|
||||
B.length src > B.length dest `shouldBe` True
|
||||
|
||||
waitFileExists :: HasCallStack => FilePath -> IO ()
|
||||
waitFileExists f = unlessM (doesFileExist f) $ waitFileExists f
|
1781
tests/ChatTests/Groups.hs
Normal file
1781
tests/ChatTests/Groups.hs
Normal file
File diff suppressed because it is too large
Load diff
1328
tests/ChatTests/Profiles.hs
Normal file
1328
tests/ChatTests/Profiles.hs
Normal file
File diff suppressed because it is too large
Load diff
442
tests/ChatTests/Utils.hs
Normal file
442
tests/ChatTests/Utils.hs
Normal file
|
@ -0,0 +1,442 @@
|
|||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module ChatTests.Utils where
|
||||
|
||||
import ChatClient
|
||||
import Control.Concurrent.Async (concurrently_)
|
||||
import Control.Concurrent.STM
|
||||
import Control.Monad (unless, when)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Char (isDigit)
|
||||
import Data.List (isPrefixOf, isSuffixOf)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.String
|
||||
import qualified Data.Text as T
|
||||
import Simplex.Chat.Controller (ChatConfig (..), ChatController (..), InlineFilesConfig (..), defaultInlineFilesConfig)
|
||||
import Simplex.Chat.Store (getUserContactProfiles)
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Messaging.Agent.Store.SQLite (withTransaction)
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import System.Directory (doesFileExist)
|
||||
import System.FilePath ((</>))
|
||||
import Test.Hspec
|
||||
|
||||
defaultPrefs :: Maybe Preferences
|
||||
defaultPrefs = Just $ toChatPrefs defaultChatPrefs
|
||||
|
||||
aliceProfile :: Profile
|
||||
aliceProfile = Profile {displayName = "alice", fullName = "Alice", image = Nothing, preferences = defaultPrefs}
|
||||
|
||||
bobProfile :: Profile
|
||||
bobProfile = Profile {displayName = "bob", fullName = "Bob", image = Just (ImageData "data:image/png;base64,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"), preferences = defaultPrefs}
|
||||
|
||||
cathProfile :: Profile
|
||||
cathProfile = Profile {displayName = "cath", fullName = "Catherine", image = Nothing, preferences = defaultPrefs}
|
||||
|
||||
danProfile :: Profile
|
||||
danProfile = Profile {displayName = "dan", fullName = "Daniel", image = Nothing, preferences = defaultPrefs}
|
||||
|
||||
versionTestMatrix2 :: (HasCallStack => TestCC -> TestCC -> IO ()) -> SpecWith FilePath
|
||||
versionTestMatrix2 runTest = do
|
||||
it "v2" $ testChat2 aliceProfile bobProfile runTest
|
||||
it "v1" $ testChatCfg2 testCfgV1 aliceProfile bobProfile runTest
|
||||
it "v1 to v2" $ runTestCfg2 testCfg testCfgV1 runTest
|
||||
it "v2 to v1" $ runTestCfg2 testCfgV1 testCfg runTest
|
||||
|
||||
versionTestMatrix3 :: (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> SpecWith FilePath
|
||||
versionTestMatrix3 runTest = do
|
||||
it "v2" $ testChat3 aliceProfile bobProfile cathProfile runTest
|
||||
|
||||
-- it "v1" $ testChatCfg3 testCfgV1 aliceProfile bobProfile cathProfile runTest
|
||||
-- it "v1 to v2" $ runTestCfg3 testCfg testCfgV1 testCfgV1 runTest
|
||||
-- it "v2+v1 to v2" $ runTestCfg3 testCfg testCfg testCfgV1 runTest
|
||||
-- it "v2 to v1" $ runTestCfg3 testCfgV1 testCfg testCfg runTest
|
||||
-- it "v2+v1 to v1" $ runTestCfg3 testCfgV1 testCfg testCfgV1 runTest
|
||||
|
||||
inlineCfg :: Integer -> ChatConfig
|
||||
inlineCfg n = testCfg {inlineFiles = defaultInlineFilesConfig {sendChunks = 0, offerChunks = n, receiveChunks = n}}
|
||||
|
||||
fileTestMatrix2 :: (HasCallStack => TestCC -> TestCC -> IO ()) -> SpecWith FilePath
|
||||
fileTestMatrix2 runTest = do
|
||||
it "via connection" $ runTestCfg2 viaConn viaConn runTest
|
||||
it "inline (accepting)" $ runTestCfg2 inline inline runTest
|
||||
it "via connection (inline offered)" $ runTestCfg2 inline viaConn runTest
|
||||
it "via connection (inline supported)" $ runTestCfg2 viaConn inline runTest
|
||||
where
|
||||
inline = inlineCfg 100
|
||||
viaConn = inlineCfg 0
|
||||
|
||||
fileTestMatrix3 :: (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> SpecWith FilePath
|
||||
fileTestMatrix3 runTest = do
|
||||
it "via connection" $ runTestCfg3 viaConn viaConn viaConn runTest
|
||||
it "inline" $ runTestCfg3 inline inline inline runTest
|
||||
it "via connection (inline offered)" $ runTestCfg3 inline viaConn viaConn runTest
|
||||
it "via connection (inline supported)" $ runTestCfg3 viaConn inline inline runTest
|
||||
where
|
||||
inline = inlineCfg 100
|
||||
viaConn = inlineCfg 0
|
||||
|
||||
runTestCfg2 :: ChatConfig -> ChatConfig -> (HasCallStack => TestCC -> TestCC -> IO ()) -> FilePath -> IO ()
|
||||
runTestCfg2 aliceCfg bobCfg runTest tmp =
|
||||
withNewTestChatCfg tmp aliceCfg "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatCfg tmp bobCfg "bob" bobProfile $ \bob ->
|
||||
runTest alice bob
|
||||
|
||||
runTestCfg3 :: ChatConfig -> ChatConfig -> ChatConfig -> (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> FilePath -> IO ()
|
||||
runTestCfg3 aliceCfg bobCfg cathCfg runTest tmp =
|
||||
withNewTestChatCfg tmp aliceCfg "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatCfg tmp bobCfg "bob" bobProfile $ \bob ->
|
||||
withNewTestChatCfg tmp cathCfg "cath" cathProfile $ \cath ->
|
||||
runTest alice bob cath
|
||||
|
||||
withTestChatGroup3Connected :: HasCallStack => FilePath -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
||||
withTestChatGroup3Connected tmp dbPrefix action = do
|
||||
withTestChat tmp dbPrefix $ \cc -> do
|
||||
cc <## "2 contacts connected (use /cs for the list)"
|
||||
cc <## "#team: connected to server(s)"
|
||||
action cc
|
||||
|
||||
withTestChatGroup3Connected' :: HasCallStack => FilePath -> String -> IO ()
|
||||
withTestChatGroup3Connected' tmp dbPrefix = withTestChatGroup3Connected tmp dbPrefix $ \_ -> pure ()
|
||||
|
||||
withTestChatContactConnected :: HasCallStack => FilePath -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
||||
withTestChatContactConnected tmp dbPrefix action =
|
||||
withTestChat tmp dbPrefix $ \cc -> do
|
||||
cc <## "1 contacts connected (use /cs for the list)"
|
||||
action cc
|
||||
|
||||
withTestChatContactConnected' :: HasCallStack => FilePath -> String -> IO ()
|
||||
withTestChatContactConnected' tmp dbPrefix = withTestChatContactConnected tmp dbPrefix $ \_ -> pure ()
|
||||
|
||||
withTestChatContactConnectedV1 :: HasCallStack => FilePath -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
||||
withTestChatContactConnectedV1 tmp dbPrefix action =
|
||||
withTestChatV1 tmp dbPrefix $ \cc -> do
|
||||
cc <## "1 contacts connected (use /cs for the list)"
|
||||
action cc
|
||||
|
||||
withTestChatContactConnectedV1' :: HasCallStack => FilePath -> String -> IO ()
|
||||
withTestChatContactConnectedV1' tmp dbPrefix = withTestChatContactConnectedV1 tmp dbPrefix $ \_ -> pure ()
|
||||
|
||||
-- | test sending direct messages
|
||||
(<##>) :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
cc1 <##> cc2 = do
|
||||
name1 <- userName cc1
|
||||
name2 <- userName cc2
|
||||
cc1 #> ("@" <> name2 <> " hi")
|
||||
cc2 <# (name1 <> "> hi")
|
||||
cc2 #> ("@" <> name1 <> " hey")
|
||||
cc1 <# (name2 <> "> hey")
|
||||
|
||||
(##>) :: HasCallStack => TestCC -> String -> IO ()
|
||||
cc ##> cmd = do
|
||||
cc `send` cmd
|
||||
cc <## cmd
|
||||
|
||||
(#>) :: HasCallStack => TestCC -> String -> IO ()
|
||||
cc #> cmd = do
|
||||
cc `send` cmd
|
||||
cc <# cmd
|
||||
|
||||
(?#>) :: HasCallStack => TestCC -> String -> IO ()
|
||||
cc ?#> cmd = do
|
||||
cc `send` cmd
|
||||
cc <# ("i " <> cmd)
|
||||
|
||||
(#$>) :: (Eq a, Show a, HasCallStack) => TestCC -> (String, String -> a, a) -> Expectation
|
||||
cc #$> (cmd, f, res) = do
|
||||
cc ##> cmd
|
||||
(f <$> getTermLine cc) `shouldReturn` res
|
||||
|
||||
chat :: String -> [(Int, String)]
|
||||
chat = map (\(a, _, _) -> a) . chat''
|
||||
|
||||
chat' :: String -> [((Int, String), Maybe (Int, String))]
|
||||
chat' = map (\(a, b, _) -> (a, b)) . chat''
|
||||
|
||||
chatF :: String -> [((Int, String), Maybe String)]
|
||||
chatF = map (\(a, _, c) -> (a, c)) . chat''
|
||||
|
||||
chat'' :: String -> [((Int, String), Maybe (Int, String), Maybe String)]
|
||||
chat'' = read
|
||||
|
||||
chatFeatures :: [(Int, String)]
|
||||
chatFeatures = map (\(a, _, _) -> a) chatFeatures''
|
||||
|
||||
chatFeatures' :: [((Int, String), Maybe (Int, String))]
|
||||
chatFeatures' = map (\(a, b, _) -> (a, b)) chatFeatures''
|
||||
|
||||
chatFeaturesF :: [((Int, String), Maybe String)]
|
||||
chatFeaturesF = map (\(a, _, c) -> (a, c)) chatFeatures''
|
||||
|
||||
chatFeatures'' :: [((Int, String), Maybe (Int, String), Maybe String)]
|
||||
chatFeatures'' = [((0, "Disappearing messages: off"), Nothing, Nothing), ((0, "Full deletion: off"), Nothing, Nothing), ((0, "Voice messages: enabled"), Nothing, Nothing)]
|
||||
|
||||
groupFeatures :: [(Int, String)]
|
||||
groupFeatures = map (\(a, _, _) -> a) groupFeatures''
|
||||
|
||||
groupFeatures'' :: [((Int, String), Maybe (Int, String), Maybe String)]
|
||||
groupFeatures'' = [((0, "Disappearing messages: off"), Nothing, Nothing), ((0, "Direct messages: on"), Nothing, Nothing), ((0, "Full deletion: off"), Nothing, Nothing), ((0, "Voice messages: on"), Nothing, Nothing)]
|
||||
|
||||
itemId :: Int -> String
|
||||
itemId i = show $ length chatFeatures + i
|
||||
|
||||
(@@@) :: HasCallStack => TestCC -> [(String, String)] -> Expectation
|
||||
(@@@) = getChats mapChats
|
||||
|
||||
mapChats :: [(String, String, Maybe ConnStatus)] -> [(String, String)]
|
||||
mapChats = map $ \(ldn, msg, _) -> (ldn, msg)
|
||||
|
||||
chats :: String -> [(String, String)]
|
||||
chats = mapChats . read
|
||||
|
||||
(@@@!) :: HasCallStack => TestCC -> [(String, String, Maybe ConnStatus)] -> Expectation
|
||||
(@@@!) = getChats id
|
||||
|
||||
getChats :: HasCallStack => (Eq a, Show a) => ([(String, String, Maybe ConnStatus)] -> [a]) -> TestCC -> [a] -> Expectation
|
||||
getChats f cc res = do
|
||||
cc ##> "/_get chats 1 pcc=on"
|
||||
line <- getTermLine cc
|
||||
f (read line) `shouldMatchList` res
|
||||
|
||||
send :: TestCC -> String -> IO ()
|
||||
send TestCC {chatController = cc} cmd = atomically $ writeTBQueue (inputQ cc) cmd
|
||||
|
||||
(<##) :: HasCallStack => TestCC -> String -> Expectation
|
||||
cc <## line = do
|
||||
l <- getTermLine cc
|
||||
when (l /= line) $ print ("expected: " <> line, ", got: " <> l)
|
||||
l `shouldBe` line
|
||||
|
||||
(<##.) :: HasCallStack => TestCC -> String -> Expectation
|
||||
cc <##. line = do
|
||||
l <- getTermLine cc
|
||||
let prefix = line `isPrefixOf` l
|
||||
unless prefix $ print ("expected to start from: " <> line, ", got: " <> l)
|
||||
prefix `shouldBe` True
|
||||
|
||||
(<#.) :: HasCallStack => TestCC -> String -> Expectation
|
||||
cc <#. line = do
|
||||
l <- dropTime <$> getTermLine cc
|
||||
let prefix = line `isPrefixOf` l
|
||||
unless prefix $ print ("expected to start from: " <> line, ", got: " <> l)
|
||||
prefix `shouldBe` True
|
||||
|
||||
(<##..) :: HasCallStack => TestCC -> [String] -> Expectation
|
||||
cc <##.. ls = do
|
||||
l <- getTermLine cc
|
||||
let prefix = any (`isPrefixOf` l) ls
|
||||
unless prefix $ print ("expected to start from one of: " <> show ls, ", got: " <> l)
|
||||
prefix `shouldBe` True
|
||||
|
||||
data ConsoleResponse = ConsoleString String | WithTime String | EndsWith String
|
||||
deriving (Show)
|
||||
|
||||
instance IsString ConsoleResponse where fromString = ConsoleString
|
||||
|
||||
-- this assumes that the string can only match one option
|
||||
getInAnyOrder :: HasCallStack => (String -> String) -> TestCC -> [ConsoleResponse] -> Expectation
|
||||
getInAnyOrder _ _ [] = pure ()
|
||||
getInAnyOrder f cc ls = do
|
||||
line <- f <$> getTermLine cc
|
||||
let rest = filter (not . expected line) ls
|
||||
if length rest < length ls
|
||||
then getInAnyOrder f cc rest
|
||||
else error $ "unexpected output: " <> line
|
||||
where
|
||||
expected :: String -> ConsoleResponse -> Bool
|
||||
expected l = \case
|
||||
ConsoleString s -> l == s
|
||||
WithTime s -> dropTime_ l == Just s
|
||||
EndsWith s -> s `isSuffixOf` l
|
||||
|
||||
(<###) :: HasCallStack => TestCC -> [ConsoleResponse] -> Expectation
|
||||
(<###) = getInAnyOrder id
|
||||
|
||||
(<##?) :: HasCallStack => TestCC -> [ConsoleResponse] -> Expectation
|
||||
(<##?) = getInAnyOrder dropTime
|
||||
|
||||
(<#) :: HasCallStack => TestCC -> String -> Expectation
|
||||
cc <# line = (dropTime <$> getTermLine cc) `shouldReturn` line
|
||||
|
||||
(?<#) :: HasCallStack => TestCC -> String -> Expectation
|
||||
cc ?<# line = (dropTime <$> getTermLine cc) `shouldReturn` "i " <> line
|
||||
|
||||
($<#) :: HasCallStack => (TestCC, String) -> String -> Expectation
|
||||
(cc, uName) $<# line = (dropTime . dropUser uName <$> getTermLine cc) `shouldReturn` line
|
||||
|
||||
(</) :: HasCallStack => TestCC -> Expectation
|
||||
(</) = (<// 500000)
|
||||
|
||||
(<#?) :: HasCallStack => TestCC -> TestCC -> Expectation
|
||||
cc1 <#? cc2 = do
|
||||
name <- userName cc2
|
||||
sName <- showName cc2
|
||||
cc2 <## "connection request sent!"
|
||||
cc1 <## (sName <> " wants to connect to you!")
|
||||
cc1 <## ("to accept: /ac " <> name)
|
||||
cc1 <## ("to reject: /rc " <> name <> " (the sender will NOT be notified)")
|
||||
|
||||
dropUser :: HasCallStack => String -> String -> String
|
||||
dropUser uName msg = fromMaybe err $ dropUser_ uName msg
|
||||
where
|
||||
err = error $ "invalid user: " <> msg
|
||||
|
||||
dropUser_ :: String -> String -> Maybe String
|
||||
dropUser_ uName msg = do
|
||||
let userPrefix = "[user: " <> uName <> "] "
|
||||
if userPrefix `isPrefixOf` msg
|
||||
then Just $ drop (length userPrefix) msg
|
||||
else Nothing
|
||||
|
||||
dropTime :: HasCallStack => String -> String
|
||||
dropTime msg = fromMaybe err $ dropTime_ msg
|
||||
where
|
||||
err = error $ "invalid time: " <> msg
|
||||
|
||||
dropTime_ :: String -> Maybe String
|
||||
dropTime_ msg = case splitAt 6 msg of
|
||||
([m, m', ':', s, s', ' '], text) ->
|
||||
if all isDigit [m, m', s, s'] then Just text else Nothing
|
||||
_ -> Nothing
|
||||
|
||||
getInvitation :: HasCallStack => TestCC -> IO String
|
||||
getInvitation cc = do
|
||||
cc <## "pass this invitation link to your contact (via another channel):"
|
||||
cc <## ""
|
||||
inv <- getTermLine cc
|
||||
cc <## ""
|
||||
cc <## "and ask them to connect: /c <invitation_link_above>"
|
||||
pure inv
|
||||
|
||||
getContactLink :: HasCallStack => TestCC -> Bool -> IO String
|
||||
getContactLink cc created = do
|
||||
cc <## if created then "Your new chat address is created!" else "Your chat address:"
|
||||
cc <## ""
|
||||
link <- getTermLine cc
|
||||
cc <## ""
|
||||
cc <## "Anybody can send you contact requests with: /c <contact_link_above>"
|
||||
cc <## "to show it again: /sa"
|
||||
cc <## "to delete it: /da (accepted contacts will remain connected)"
|
||||
pure link
|
||||
|
||||
getGroupLink :: HasCallStack => TestCC -> String -> Bool -> IO String
|
||||
getGroupLink cc gName created = do
|
||||
cc <## if created then "Group link is created!" else "Group link:"
|
||||
cc <## ""
|
||||
link <- getTermLine cc
|
||||
cc <## ""
|
||||
cc <## "Anybody can connect to you and join group with: /c <group_link_above>"
|
||||
cc <## ("to show it again: /show link #" <> gName)
|
||||
cc <## ("to delete it: /delete link #" <> gName <> " (joined members will remain connected to you)")
|
||||
pure link
|
||||
|
||||
hasContactProfiles :: HasCallStack => TestCC -> [ContactName] -> Expectation
|
||||
hasContactProfiles cc names =
|
||||
getContactProfiles cc >>= \ps -> ps `shouldMatchList` names
|
||||
|
||||
getContactProfiles :: TestCC -> IO [ContactName]
|
||||
getContactProfiles cc = do
|
||||
user_ <- readTVarIO (currentUser $ chatController cc)
|
||||
case user_ of
|
||||
Nothing -> pure []
|
||||
Just user -> do
|
||||
profiles <- withTransaction (chatStore $ chatController cc) $ \db -> getUserContactProfiles db user
|
||||
pure $ map (\Profile {displayName} -> displayName) profiles
|
||||
|
||||
lastItemId :: HasCallStack => TestCC -> IO String
|
||||
lastItemId cc = do
|
||||
cc ##> "/last_item_id"
|
||||
getTermLine cc
|
||||
|
||||
showActiveUser :: HasCallStack => TestCC -> String -> Expectation
|
||||
showActiveUser cc name = do
|
||||
cc <## ("user profile: " <> name)
|
||||
cc <## "use /p <display name> [<full name>] to change it"
|
||||
cc <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
connectUsers :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
connectUsers cc1 cc2 = do
|
||||
name1 <- showName cc1
|
||||
name2 <- showName cc2
|
||||
cc1 ##> "/c"
|
||||
inv <- getInvitation cc1
|
||||
cc2 ##> ("/c " <> inv)
|
||||
cc2 <## "confirmation sent!"
|
||||
concurrently_
|
||||
(cc2 <## (name1 <> ": contact is connected"))
|
||||
(cc1 <## (name2 <> ": contact is connected"))
|
||||
|
||||
showName :: TestCC -> IO String
|
||||
showName (TestCC ChatController {currentUser} _ _ _ _) = do
|
||||
Just User {localDisplayName, profile = LocalProfile {fullName}} <- readTVarIO currentUser
|
||||
pure . T.unpack $ localDisplayName <> optionalFullName localDisplayName fullName
|
||||
|
||||
createGroup2 :: HasCallStack => String -> TestCC -> TestCC -> IO ()
|
||||
createGroup2 gName cc1 cc2 = do
|
||||
connectUsers cc1 cc2
|
||||
name2 <- userName cc2
|
||||
cc1 ##> ("/g " <> gName)
|
||||
cc1 <## ("group #" <> gName <> " is created")
|
||||
cc1 <## ("to add members use /a " <> gName <> " <name> or /create link #" <> gName)
|
||||
addMember gName cc1 cc2 GRAdmin
|
||||
cc2 ##> ("/j " <> gName)
|
||||
concurrently_
|
||||
(cc1 <## ("#" <> gName <> ": " <> name2 <> " joined the group"))
|
||||
(cc2 <## ("#" <> gName <> ": you joined the group"))
|
||||
|
||||
createGroup3 :: HasCallStack => String -> TestCC -> TestCC -> TestCC -> IO ()
|
||||
createGroup3 gName cc1 cc2 cc3 = do
|
||||
createGroup2 gName cc1 cc2
|
||||
connectUsers cc1 cc3
|
||||
name3 <- userName cc3
|
||||
sName2 <- showName cc2
|
||||
sName3 <- showName cc3
|
||||
addMember gName cc1 cc3 GRAdmin
|
||||
cc3 ##> ("/j " <> gName)
|
||||
concurrentlyN_
|
||||
[ cc1 <## ("#" <> gName <> ": " <> name3 <> " joined the group"),
|
||||
do
|
||||
cc3 <## ("#" <> gName <> ": you joined the group")
|
||||
cc3 <## ("#" <> gName <> ": member " <> sName2 <> " is connected"),
|
||||
do
|
||||
cc2 <## ("#" <> gName <> ": alice added " <> sName3 <> " to the group (connecting...)")
|
||||
cc2 <## ("#" <> gName <> ": new member " <> name3 <> " is connected")
|
||||
]
|
||||
|
||||
addMember :: HasCallStack => String -> TestCC -> TestCC -> GroupMemberRole -> IO ()
|
||||
addMember gName inviting invitee role = do
|
||||
name1 <- userName inviting
|
||||
memName <- userName invitee
|
||||
inviting ##> ("/a " <> gName <> " " <> memName <> " " <> B.unpack (strEncode role))
|
||||
concurrentlyN_
|
||||
[ inviting <## ("invitation to join the group #" <> gName <> " sent to " <> memName),
|
||||
do
|
||||
invitee <## ("#" <> gName <> ": " <> name1 <> " invites you to join the group as " <> B.unpack (strEncode role))
|
||||
invitee <## ("use /j " <> gName <> " to accept")
|
||||
]
|
||||
|
||||
checkActionDeletesFile :: HasCallStack => FilePath -> IO () -> IO ()
|
||||
checkActionDeletesFile file action = do
|
||||
fileExistsBefore <- doesFileExist file
|
||||
fileExistsBefore `shouldBe` True
|
||||
action
|
||||
fileExistsAfter <- doesFileExist file
|
||||
fileExistsAfter `shouldBe` False
|
||||
|
||||
startFileTransferWithDest' :: HasCallStack => TestCC -> TestCC -> String -> String -> Maybe String -> IO ()
|
||||
startFileTransferWithDest' cc1 cc2 fileName fileSize fileDest_ = do
|
||||
name1 <- userName cc1
|
||||
name2 <- userName cc2
|
||||
cc1 #> ("/f @" <> name2 <> " ./tests/fixtures/" <> fileName)
|
||||
cc1 <## "use /fc 1 to cancel sending"
|
||||
cc2 <# (name1 <> "> sends file " <> fileName <> " (" <> fileSize <> ")")
|
||||
cc2 <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
cc2 ##> ("/fr 1" <> maybe "" (" " <>) fileDest_)
|
||||
cc2 <## ("saving file 1 from " <> name1 <> " to " <> maybe id (</>) fileDest_ fileName)
|
||||
concurrently_
|
||||
(cc2 <## ("started receiving file 1 (" <> fileName <> ") from " <> name1))
|
||||
(cc1 <## ("started sending file 1 (" <> fileName <> ") to " <> name2))
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module MobileTests where
|
||||
|
||||
import ChatTests
|
||||
import ChatTests.Utils
|
||||
import Control.Monad.Except
|
||||
import Simplex.Chat.Mobile
|
||||
import Simplex.Chat.Store
|
||||
|
|
Loading…
Add table
Reference in a new issue