SimpleX-Chat/tests/ChatTests/Local.hs

190 lines
7 KiB
Haskell
Raw Normal View History

core: add notes chat type (#3568) * Add chat type "self" * rename to Notes * cover more things * remove quote, tweak sql * resolve comments * constrain ACIQDirection to exclude CTLocal * add CILocalRcv handling * plug in migrations and tests * cover more API, implement new folders * working create/send/tail * remove interaction with messages * add note deletion (api-only) * add folder deletion * add getLocalChatItemIdByText * add APICreateChatItem and files * add protocol check for getFileTransfer protocol * replace FTLocal with createLocalFile * add chat previews * add folder clear * add reactions * add read/unread * add note updates * resolve some comments * remove local reactions * remove folder names, deletion, add autocreate * add file deletion check * add preview pagination test * add per-item file deletion check * pull mkChatItem out of createLocal to prevent ci record updates * use - as notes name * bump migration ts * update schema * resolve comments * add chat pagination test * use chat queries from Direct instead * evict note folders from createUserRecord * switch to - for note folder chat type prefix and use empty name * fix getLocalChatXxx * add explicit createCCNoteFolder for tests * use overloadedstrings for single-line queries * add suggested chat list tests * add notes chat to a user-creating test * throw correct error for missing file * remove unique check from schema * add UndecidableInstances for ghc8.10 * switch to * for chat type sigil * add file safety test * add drop index * remove indentation * remove repeated folder * remove redundant filter query, NoteFolderName * don't attempt to cancel local files when deleting chat item * rename function * fix comment * rename * fix merge * fix typo * remove editable limit * restore comment * remove local file cancel * Revert "remove editable limit" This reverts commit 65df55caf88df8538c593dfd77b3c62e9c4bce06. * refactor --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-11 19:01:44 +02:00
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PostfixOperators #-}
module ChatTests.Local where
import ChatClient
import ChatTests.ChatList (getChats_)
import ChatTests.Utils
import Data.Time (getCurrentTime)
import Data.Time.Format.ISO8601 (iso8601Show)
import Simplex.Chat.Controller (ChatConfig (..), InlineFilesConfig (..), defaultInlineFilesConfig)
import System.Directory (copyFile, doesFileExist)
import System.FilePath ((</>))
import Test.Hspec hiding (it)
core: add notes chat type (#3568) * Add chat type "self" * rename to Notes * cover more things * remove quote, tweak sql * resolve comments * constrain ACIQDirection to exclude CTLocal * add CILocalRcv handling * plug in migrations and tests * cover more API, implement new folders * working create/send/tail * remove interaction with messages * add note deletion (api-only) * add folder deletion * add getLocalChatItemIdByText * add APICreateChatItem and files * add protocol check for getFileTransfer protocol * replace FTLocal with createLocalFile * add chat previews * add folder clear * add reactions * add read/unread * add note updates * resolve some comments * remove local reactions * remove folder names, deletion, add autocreate * add file deletion check * add preview pagination test * add per-item file deletion check * pull mkChatItem out of createLocal to prevent ci record updates * use - as notes name * bump migration ts * update schema * resolve comments * add chat pagination test * use chat queries from Direct instead * evict note folders from createUserRecord * switch to - for note folder chat type prefix and use empty name * fix getLocalChatXxx * add explicit createCCNoteFolder for tests * use overloadedstrings for single-line queries * add suggested chat list tests * add notes chat to a user-creating test * throw correct error for missing file * remove unique check from schema * add UndecidableInstances for ghc8.10 * switch to * for chat type sigil * add file safety test * add drop index * remove indentation * remove repeated folder * remove redundant filter query, NoteFolderName * don't attempt to cancel local files when deleting chat item * rename function * fix comment * rename * fix merge * fix typo * remove editable limit * restore comment * remove local file cancel * Revert "remove editable limit" This reverts commit 65df55caf88df8538c593dfd77b3c62e9c4bce06. * refactor --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-11 19:01:44 +02:00
import UnliftIO.Async (concurrently_)
chatLocalChatsTests :: SpecWith FilePath
chatLocalChatsTests = do
describe "note folders" $ do
it "create folders, add notes, read, search" testNotes
it "switch users" testUserNotes
it "preview pagination for notes" testPreviewsPagination
it "chat pagination" testChatPagination
it "stores files" testFiles
it "deleting files does not interfere with other chat types" testOtherFiles
testNotes :: FilePath -> IO ()
testNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
createCCNoteFolder alice
alice ##> "/contacts"
-- not a contact
alice /* "keep in mind"
alice ##> "/tail"
alice <# "* keep in mind"
alice ##> "/chats"
alice <# "* keep in mind"
alice ##> "/? keep"
alice <# "* keep in mind"
alice #$> ("/_read chat *1 from=1 to=100", id, "ok")
alice ##> "/_unread chat *1 on"
alice <## "ok"
alice ##> "/_delete item *1 1 internal"
alice <## "message deleted"
alice ##> "/tail"
alice ##> "/chats"
alice /* "ahoy!"
alice ##> "/_update item *1 1 text Greetings."
alice ##> "/tail *"
alice <# "* Greetings."
testUserNotes :: FilePath -> IO ()
testUserNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
createCCNoteFolder alice
alice /* "keep in mind"
alice ##> "/tail"
alice <# "* keep in mind"
alice ##> "/create user secret"
alice <## "user profile: secret"
alice <## "use /p <display name> to change it"
alice <## "(the updated profile will be sent to all your contacts)"
alice ##> "/tail"
alice ##> "/_delete item *1 1 internal"
alice <## "chat db error: SENoteFolderNotFound {noteFolderId = 1}"
testPreviewsPagination :: FilePath -> IO ()
testPreviewsPagination tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
createCCNoteFolder alice
tsS <- iso8601Show <$> getCurrentTime
alice /* "first"
tsM <- iso8601Show <$> getCurrentTime
alice /* "last"
tsE <- iso8601Show <$> getCurrentTime
-- there's only one folder that got updated after tsM and before tsE
getChats_ alice "count=3" [("*", "last")]
getChats_ alice ("after=" <> tsE <> " count=10") []
getChats_ alice ("after=" <> tsS <> " count=10") [("*", "last")]
getChats_ alice ("before=" <> tsM <> " count=10") []
getChats_ alice ("before=" <> tsE <> " count=10") [("*", "last")]
getChats_ alice ("before=" <> tsS <> " count=10") []
testChatPagination :: FilePath -> IO ()
testChatPagination tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
createCCNoteFolder alice
alice /* "hello world"
alice /* "memento mori"
alice /* "knock-knock"
alice /* "who's there?"
alice #$> ("/_get chat *1 count=100", chat, [(1, "hello world"), (1, "memento mori"), (1, "knock-knock"), (1, "who's there?")])
alice #$> ("/_get chat *1 count=1", chat, [(1, "who's there?")])
alice #$> ("/_get chat *1 after=2 count=10", chat, [(1, "knock-knock"), (1, "who's there?")])
alice #$> ("/_get chat *1 after=2 count=2", chat, [(1, "knock-knock"), (1, "who's there?")])
alice #$> ("/_get chat *1 after=1 count=2", chat, [(1, "memento mori"), (1, "knock-knock")])
alice #$> ("/_get chat *1 before=3 count=10", chat, [(1, "hello world"), (1, "memento mori")])
alice #$> ("/_get chat *1 before=3 count=2", chat, [(1, "hello world"), (1, "memento mori")])
alice #$> ("/_get chat *1 before=4 count=2", chat, [(1, "memento mori"), (1, "knock-knock")])
alice #$> ("/_get chat *1 count=10 search=k-k", chat, [(1, "knock-knock")])
testFiles :: FilePath -> IO ()
testFiles tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
-- setup
createCCNoteFolder alice
let files = "./tests/tmp/app_files"
alice ##> ("/_files_folder " <> files)
alice <## "ok"
-- ui-like upload
let source = "./tests/fixtures/test.jpg"
let stored = files </> "test.jpg"
copyFile source stored
alice ##> "/_create *1 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"hi myself\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
alice <# "* hi myself"
alice <# "* file 1 (test.jpg)"
alice ##> "/tail"
alice <# "* hi myself"
alice <# "* file 1 (test.jpg)"
alice ##> "/_get chat *1 count=100"
r <- chatF <$> getTermLine alice
r `shouldBe` [((1, "hi myself"), Just "test.jpg")]
alice ##> "/fs 1"
alice <## "bad chat command: not supported for local files"
alice ##> "/fc 1"
alice <## "chat db error: SELocalFileNoTransfer {fileId = 1}"
-- one more file
let stored2 = files </> "another_test.jpg"
copyFile source stored2
alice ##> "/_create *1 json {\"filePath\": \"another_test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
alice <# "* file 2 (another_test.jpg)"
alice ##> "/_delete item *1 2 internal"
alice <## "message deleted"
doesFileExist stored2 `shouldReturn` False
doesFileExist stored `shouldReturn` True
alice ##> "/clear *"
alice ##> "/fs 1"
alice <## "chat db error: SEChatItemNotFoundByFileId {fileId = 1}"
alice ##> "/tail"
doesFileExist stored `shouldReturn` False
testOtherFiles :: FilePath -> IO ()
testOtherFiles =
testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do
connectUsers alice bob
createCCNoteFolder 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")
bob /* "test"
bob ##> "/tail *"
bob <# "* test"
bob ##> "/clear *"
bob ##> "/tail *"
bob ##> "/fs 1"
bob <## "receiving file 1 (test.jpg) complete, path: test.jpg"
doesFileExist "./tests/tmp/test.jpg" `shouldReturn` True
where
cfg = testCfg {inlineFiles = defaultInlineFilesConfig {offerChunks = 100, sendChunks = 100, receiveChunks = 100}}