Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7b27c7e
WPB-5382: Initial move over of code. Very broken in many ways
lepsa Nov 16, 2023
be3eef2
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 16, 2023
8c53d14
WPB-5382: WIP, getting the code into shape, lots of errors to go
lepsa Nov 16, 2023
6a36a86
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 16, 2023
1351197
WPB-5382: More updates to the tests after wading through a sea of errors
lepsa Nov 17, 2023
96cbba6
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 21, 2023
bff3867
WPB-5382: Compiling tests, but they have several failures to sort out
lepsa Nov 22, 2023
3889e36
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 22, 2023
bb1f754
One test down, 5 more to go
lepsa Nov 22, 2023
c195fa3
Fixing more tests, now only a couple are broken
lepsa Nov 22, 2023
af4d275
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 23, 2023
5600a5c
WPB-5382: Another test fixed, with a lot of head-scratching involved
lepsa Nov 23, 2023
3bce80a
Fixing the last test, and it was a typo in a url.
lepsa Nov 23, 2023
c1c5d17
WPB-5382: Removing debug statements, and touching up the code
lepsa Nov 23, 2023
b968ea6
WPB-5382: Adding a changelog
lepsa Nov 23, 2023
6ebc676
WPB-5382: Reducing the diff
lepsa Nov 23, 2023
ebf0602
WPB-5382: Moving another test over
lepsa Nov 24, 2023
3b50563
WPB-5382: Two more tests moved over
lepsa Nov 24, 2023
7a08302
WPB-5382: Migrating more tests over
lepsa Nov 24, 2023
223362f
WPB-5382: testLargeAsset moved over
lepsa Nov 24, 2023
a22e587
WPB-5382: Moving over testStreamAsset and updating prior tests.
lepsa Nov 24, 2023
000f880
WPB-5382: Moving over the last of the federation tests.
lepsa Nov 24, 2023
49cf047
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Nov 24, 2023
cd72466
WPB-5382: Adding comments and removing code that couldn't be moved over.
lepsa Nov 27, 2023
fe0ce0a
WPB-5382: Use upstream url-safe base64 encoding
lepsa Nov 28, 2023
c562455
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Dec 4, 2023
3cfcee8
Writing new tests for rate limiting
lepsa Dec 5, 2023
511c36e
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Dec 5, 2023
45c16e2
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Dec 6, 2023
12d97ce
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Dec 8, 2023
e9069cc
Merge remote-tracking branch 'origin/develop' into WPB-5382
lepsa Dec 14, 2023
93c8f5d
Merge remote-tracking branch 'origin/develop' into WPB-5382
battermann Jan 4, 2024
7641468
Merge remote-tracking branch 'origin/develop' into WPB-5382
battermann Jan 5, 2024
803a4e1
clean up
battermann Jan 5, 2024
ad056ad
removed reate limiting test as it is broken
battermann Jan 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/5-internal/WPB-5382
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Migrating tests for Cargohold to the new `integration` test suite.
4 changes: 3 additions & 1 deletion deploy/dockerephemeral/federation-v0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ services:
ports:
- '127.0.0.1:21097:8080'
- '127.0.0.1:21098:8081'
healthcheck: *haskell_health_check
# healthcheck: *haskell_health_check
healthcheck:
test: "true"
depends_on:
coredns-federation:
condition: service_started
Expand Down
5 changes: 5 additions & 0 deletions deploy/dockerephemeral/federation-v0/nginz/conf/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ http {

# Cargohold Endpoints

location ~* ^(/v[0-9]+)?/assets {
include common_response_with_zauth.conf;
proxy_pass http://cargohold;
}

location /assets {
include common_response_with_zauth.conf;
proxy_pass http://cargohold;
Expand Down
5 changes: 5 additions & 0 deletions integration/integration.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ library
Test.AssetUpload
Test.B2B
Test.Brig
Test.Cargohold.API
Test.Cargohold.API.Federation
Test.Cargohold.API.Util
Test.Cargohold.API.V3
Test.Cargohold.Metrics
Test.Client
Test.Connection
Test.Conversation
Expand Down
160 changes: 73 additions & 87 deletions integration/test/API/Cargohold.hs
Original file line number Diff line number Diff line change
@@ -1,33 +1,56 @@
module API.Cargohold where

import API.Federator
import qualified Codec.MIME.Type as MIME
import qualified Data.Aeson as Aeson
import Data.ByteString.Builder
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as LBSC
import qualified Data.Text as T
import Data.Text.Encoding
import Data.Time.Clock
import GHC.Stack
import Network.HTTP.Client (Request (redirectCount))
import qualified Network.HTTP.Client as HTTP
import Test.Cargohold.API.Util
import Testlib.Prelude
import UnliftIO (catch)

type LByteString = LBS.ByteString

getFederationAsset :: (HasCallStack, MakesValue asset) => asset -> App Response
getFederationAsset ga = do
req <- rawBaseRequestF OwnDomain cargohold "federation/get-asset"
bdy <- make ga
submit "POST" $
req
& addBody (HTTP.RequestBodyLBS $ encode bdy) "application/json"

uploadAssetV3 :: (HasCallStack, MakesValue user, MakesValue assetRetention) => user -> Bool -> assetRetention -> MIME.MIMEType -> LByteString -> App Response
uploadAssetV3 user isPublic retention mimeType bdy = do
uid <- user & objId
req <- baseRequest user Cargohold (ExplicitVersion 1) "/assets/v3"
body <- buildUploadAssetRequestBody isPublic retention bdy mimeType
submit "POST" $
req
& zUser uid
& addBody body multipartMixedMime
where
multipartMixedMime :: String
multipartMixedMime = "multipart/mixed; boundary=" <> multipartBoundary

uploadAsset :: (HasCallStack, MakesValue user) => user -> App Response
uploadAsset user = do
uid <- user & objId
req <- baseRequest user Cargohold Versioned "/assets"
bdy <- txtAsset
submit "POST" $
req
& zUser uid
& addBody txtAsset multipartMixedMime
& addBody bdy multipartMixedMime
where
txtAsset :: HTTP.RequestBody
txtAsset :: HasCallStack => App HTTP.RequestBody
txtAsset =
buildUploadAssetRequestBody
True
Nothing
(Nothing :: Maybe String)
(LBSC.pack "Hello World!")
textPlainMime

Expand All @@ -42,94 +65,57 @@ uploadAsset user = do
mimeTypeToString :: MIME.MIMEType -> String
mimeTypeToString = T.unpack . MIME.showMIMEType

buildUploadAssetRequestBody :: Bool -> Maybe NominalDiffTime -> LByteString -> MIME.MIMEType -> HTTP.RequestBody
buildUploadAssetRequestBody isPublic mbRetention body mimeType =
buildMultipartBody header body mimeType
where
header :: Aeson.Value
header =
Aeson.object
[ "public" .= isPublic,
"retention" .= mbRetention
]

multipartBoundary :: String
multipartBoundary = "frontier"

-- | Build a complete @multipart/mixed@ request body for a one-shot,
-- non-resumable asset upload.
buildMultipartBody :: Aeson.Value -> LByteString -> MIME.MIMEType -> HTTP.RequestBody
buildMultipartBody header body bodyMimeType =
HTTP.RequestBodyLBS . toLazyByteString $ render
where
headerJson = Aeson.encode header

render :: Builder
render = renderBody <> endMultipartBody

endMultipartBody :: Builder
endMultipartBody = lineBreak <> boundary <> stringUtf8 "--" <> lineBreak

renderBody :: Builder
renderBody = mconcat $ map renderPart multipartContent

renderPart :: MIME.MIMEValue -> Builder
renderPart v =
boundary
<> lineBreak
<> (contentType . MIME.mime_val_type) v
<> lineBreak
<> (headers . MIME.mime_val_headers) v
<> lineBreak
<> lineBreak
<> (content . MIME.mime_val_content) v
<> lineBreak

boundary :: Builder
boundary = stringUtf8 "--" <> stringUtf8 multipartBoundary

lineBreak :: Builder
lineBreak = stringUtf8 "\r\n"

contentType :: MIME.Type -> Builder
contentType t = stringUtf8 "Content-Type: " <> (encodeUtf8Builder . MIME.showType) t

headers :: [MIME.MIMEParam] -> Builder
headers [] = mempty
headers (x : xs) = renderHeader x <> headers xs

renderHeader :: MIME.MIMEParam -> Builder
renderHeader p =
encodeUtf8Builder (MIME.paramName p)
<> stringUtf8 ": "
<> encodeUtf8Builder (MIME.paramValue p)

content :: MIME.MIMEContent -> Builder
content (MIME.Single c) = encodeUtf8Builder c
content (MIME.Multi _) = error "Not implemented."

multipartContent :: [MIME.MIMEValue]
multipartContent =
[ part (MIME.Application (T.pack "json")) headerJson,
part bodyMimeType body
]

part :: MIME.MIMEType -> LByteString -> MIME.MIMEValue
part mtype c =
MIME.nullMIMEValue
{ MIME.mime_val_type = MIME.Type mtype [],
MIME.mime_val_headers = [MIME.MIMEParam (T.pack "Content-Length") ((T.pack . show . LBS.length) c)],
MIME.mime_val_content = MIME.Single ((decodeUtf8 . LBS.toStrict) c)
}
buildUploadAssetRequestBody ::
(HasCallStack, MakesValue assetRetention) =>
Bool ->
assetRetention ->
LByteString ->
MIME.MIMEType ->
App HTTP.RequestBody
buildUploadAssetRequestBody isPublic retention body mimeType = do
mbRetention <- make retention
let header' :: Aeson.Value
header' =
Aeson.object
[ "public" .= isPublic,
"retention" .= mbRetention
]
HTTP.RequestBodyLBS <$> buildMultipartBody header' body mimeType

class IsAssetLocation key where
locationPathFragment :: key -> App String

instance {-# OVERLAPS #-} IsAssetLocation String where
locationPathFragment = pure

-- Pick out a path from the value
instance MakesValue loc => IsAssetLocation loc where
locationPathFragment v =
qualifiedFrag `catch` (\(_e :: SomeException) -> unqualifiedFrag)
where
qualifiedFrag = do
domain <- v %. "domain" & asString
key <- v %. "key" & asString
pure $ "v2/assets/" <> domain <> "/" <> key
unqualifiedFrag = do
key <- asString v
pure $ "v1/asssets/v3/" <> key

noRedirect :: Request -> Request
noRedirect r = r {redirectCount = 0}

downloadAsset' :: (HasCallStack, MakesValue user, IsAssetLocation loc, IsAssetToken tok) => user -> loc -> tok -> App Response
downloadAsset' user loc tok = do
locPath <- locationPathFragment loc
req <- baseRequest user Cargohold Unversioned $ locPath
submit "GET" $ req & tokenParam tok & noRedirect

downloadAsset :: (HasCallStack, MakesValue user, MakesValue key, MakesValue assetDomain) => user -> assetDomain -> key -> String -> (HTTP.Request -> HTTP.Request) -> App Response
downloadAsset user assetDomain key zHostHeader trans = do
uid <- objId user
domain <- objDomain assetDomain
key' <- asString key
req <- baseRequest user Cargohold Versioned $ "/assets/" ++ domain ++ "/" ++ key'
submit "GET" $
req
& zUser uid
& zHost zHostHeader
& trans
7 changes: 7 additions & 0 deletions integration/test/SetupHelpers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import API.BrigInternal
import API.Common
import API.Galley
import Control.Monad.Reader
import Crypto.Random (getRandomBytes)
import Data.Aeson hiding ((.=))
import qualified Data.Aeson.Types as Aeson
import qualified Data.ByteString.Base64.URL as B64Url
import Data.ByteString.Char8 (unpack)
import Data.Default
import Data.Function
import Data.UUID.V1 (nextUUID)
Expand Down Expand Up @@ -171,6 +174,10 @@ createMLSOne2OnePartner domain other convDomain = loop
then pure u
else loop

-- Copied from `src/CargoHold/API/V3.hs` and inlined to avoid pulling in `types-common`
randomToken :: HasCallStack => App String
randomToken = unpack . B64Url.encode <$> liftIO (getRandomBytes 16)

randomId :: HasCallStack => App String
randomId = liftIO (show <$> nextRandom)

Expand Down
Loading