Type ordinary integration probe HTTP traffic
This commit is contained in:
parent
390434bed1
commit
cc5c47f2ce
1 changed files with 1022 additions and 661 deletions
|
|
@ -6,6 +6,7 @@ import qualified Data.ByteString as BS
|
|||
import qualified Data.ByteString.Char8 as B8
|
||||
import Nuthatch.Probe.Assert
|
||||
import Nuthatch.Probe.Curl
|
||||
import Nuthatch.Probe.Http
|
||||
import Nuthatch.Probe.Oidc
|
||||
import Nuthatch.Probe.ProductClient
|
||||
import System.Exit (ExitCode (..))
|
||||
|
|
@ -25,7 +26,7 @@ import System.Process
|
|||
main :: IO ()
|
||||
main =
|
||||
withSystemTempDirectory "nuthatch-idempotency-probe" $ \directory -> do
|
||||
context <- newProbeContext directory
|
||||
context <- newProbeContext
|
||||
user <- requireEnv "NUTHATCH_OIDC_USER_A"
|
||||
session <- login context False user "idempotency"
|
||||
lane <- requireEnv "NUTHATCH_FIXTURE_LANE"
|
||||
|
|
@ -53,16 +54,16 @@ verifyEpochs context session lane ipA ipB = do
|
|||
conflict <- targetedUpload context session lane ipB operationId "conflict"
|
||||
assertContains "conflicting reuse"
|
||||
"\"result\":\"conflict\""
|
||||
(curlBody conflict)
|
||||
(probeBody conflict)
|
||||
threadDelay 3000000
|
||||
(responseA, responseB) <- concurrently
|
||||
(targetedUpload context session lane ipA operationId "second-epoch-a")
|
||||
(targetedUpload context session lane ipB operationId "second-epoch-b")
|
||||
let outcomes = [responseA, responseB]
|
||||
succeeded response =
|
||||
"\"result\":\"succeeded\"" `BS.isInfixOf` curlBody response
|
||||
"\"result\":\"succeeded\"" `BS.isInfixOf` probeBody response
|
||||
conflicted response =
|
||||
"\"result\":\"conflict\"" `BS.isInfixOf` curlBody response
|
||||
"\"result\":\"conflict\"" `BS.isInfixOf` probeBody response
|
||||
assertEqual "new epoch winner count" 1 (length (filter succeeded outcomes))
|
||||
assertEqual "new epoch conflict count" 1 (length (filter conflicted outcomes))
|
||||
let (winningBody, replayIp) =
|
||||
|
|
@ -72,13 +73,9 @@ verifyEpochs context session lane ipA ipB = do
|
|||
secondReplay <-
|
||||
targetedUpload context session lane replayIp operationId winningBody
|
||||
requireSucceededWindow "new epoch replay" secondReplay
|
||||
downloaded <- downloadFrom
|
||||
(probeBase context)
|
||||
(resolveArgs lane ipA)
|
||||
session
|
||||
"personal"
|
||||
"idempotency.txt"
|
||||
assertEqual "new epoch object body" winningBody (curlBody downloaded)
|
||||
downloaded <-
|
||||
targetedDownload context session lane ipA "personal" "idempotency.txt"
|
||||
assertEqual "new epoch object body" winningBody (probeBody downloaded)
|
||||
|
||||
verifyActiveIdentity
|
||||
:: ProbeContext
|
||||
|
|
@ -106,7 +103,7 @@ verifyActiveIdentity context session lane ipA ipB directory = do
|
|||
"first-epoch"
|
||||
assertContains "active replay after terminal window"
|
||||
"\"result\":\"pending\""
|
||||
(curlBody pending)
|
||||
(probeBody pending)
|
||||
locked <- targetedUploadAt
|
||||
context
|
||||
session
|
||||
|
|
@ -115,14 +112,14 @@ verifyActiveIdentity context session lane ipA ipB directory = do
|
|||
"active-window.bin"
|
||||
"73000000-0000-4000-8000-000000000003"
|
||||
"first-epoch"
|
||||
assertEqual "active key lock status" 200 (curlStatus locked)
|
||||
assertEqual "active key lock status" 200 (probeStatus locked)
|
||||
assertContains "active key lock"
|
||||
"\"result\":\"rejected\""
|
||||
(curlBody locked)
|
||||
(probeBody locked)
|
||||
completed <- wait active
|
||||
assertContains "active request completion"
|
||||
"\"result\":\"succeeded\""
|
||||
(curlBody completed)
|
||||
(probeBody completed)
|
||||
|
||||
targetedUpload
|
||||
:: ProbeContext
|
||||
|
|
@ -131,7 +128,7 @@ targetedUpload
|
|||
-> String
|
||||
-> String
|
||||
-> BS.ByteString
|
||||
-> IO CurlResponse
|
||||
-> IO ProbeResponse
|
||||
targetedUpload context session lane ip =
|
||||
targetedUploadAt context session lane ip "idempotency.txt"
|
||||
|
||||
|
|
@ -143,15 +140,39 @@ targetedUploadAt
|
|||
-> String
|
||||
-> String
|
||||
-> BS.ByteString
|
||||
-> IO CurlResponse
|
||||
targetedUploadAt context session lane ip path operationId =
|
||||
uploadTo
|
||||
(probeBase context)
|
||||
(resolveArgs lane ip)
|
||||
-> IO ProbeResponse
|
||||
targetedUploadAt context session lane ip path operationId body =
|
||||
uploadDeclared
|
||||
context
|
||||
session
|
||||
"personal"
|
||||
lane
|
||||
ip
|
||||
path
|
||||
operationId
|
||||
(BS.length body)
|
||||
(sha256Hex body)
|
||||
body
|
||||
|
||||
targetedDownload
|
||||
:: ProbeContext
|
||||
-> Session
|
||||
-> String
|
||||
-> String
|
||||
-> String
|
||||
-> String
|
||||
-> IO ProbeResponse
|
||||
targetedDownload context session lane ip root path = do
|
||||
cookies <- cookieHeader (sessionCookies session)
|
||||
curl
|
||||
( resolveArgs lane ip
|
||||
<> [ "--header", "Cookie: " <> B8.unpack cookies
|
||||
, probeBase context
|
||||
<> "/api/download?root="
|
||||
<> root
|
||||
<> "&path="
|
||||
<> path
|
||||
]
|
||||
)
|
||||
|
||||
uploadDeclared
|
||||
:: ProbeContext
|
||||
|
|
@ -163,14 +184,15 @@ uploadDeclared
|
|||
-> Int
|
||||
-> BS.ByteString
|
||||
-> BS.ByteString
|
||||
-> IO CurlResponse
|
||||
-> IO ProbeResponse
|
||||
uploadDeclared context session lane ip path operationId size digest body =
|
||||
withSystemTempFile "nuthatch-declared-upload" $ \bodyPath handle -> do
|
||||
BS.hPut handle body
|
||||
hClose handle
|
||||
cookies <- cookieHeader (sessionCookies session)
|
||||
curl
|
||||
( resolveArgs lane ip
|
||||
<> [ "--cookie", sessionCookies session
|
||||
<> [ "--header", "Cookie: " <> B8.unpack cookies
|
||||
, "--header", "Content-Type: application/octet-stream"
|
||||
, "--header", "X-Declared-Size: " <> show size
|
||||
, "--header", "X-Content-SHA256: " <> B8.unpack digest
|
||||
|
|
@ -193,8 +215,9 @@ slowUpload
|
|||
-> FilePath
|
||||
-> String
|
||||
-> BS.ByteString
|
||||
-> IO CurlResponse
|
||||
-> IO ProbeResponse
|
||||
slowUpload context session lane ip directory operationId body = do
|
||||
cookies <- cookieHeader (sessionCookies session)
|
||||
let outputPath = directory <> "/active-upload-response"
|
||||
statusPath = directory <> "/active-upload-status"
|
||||
firstChunk = BS.take 65536 body
|
||||
|
|
@ -204,7 +227,7 @@ slowUpload context session lane ip directory operationId body = do
|
|||
, "--silent"
|
||||
, "--show-error"
|
||||
, "--resolve", "nuthatch-" <> lane <> ":8080:" <> ip
|
||||
, "--cookie", sessionCookies session
|
||||
, "--header", "Cookie: " <> B8.unpack cookies
|
||||
, "--header", "Content-Type: application/octet-stream"
|
||||
, "--header", "X-Declared-Size: " <> show (BS.length body)
|
||||
, "--header", "X-Content-SHA256: " <> B8.unpack (sha256Hex body)
|
||||
|
|
@ -240,10 +263,10 @@ slowUpload context session lane ip directory operationId body = do
|
|||
status <- case reads (B8.unpack statusBytes) of
|
||||
[(value, "")] -> pure value
|
||||
_ -> fail "slow upload returned invalid HTTP status"
|
||||
pure CurlResponse
|
||||
{ curlStatus = status
|
||||
, curlHeaders = []
|
||||
, curlBody = responseBody
|
||||
pure ProbeResponse
|
||||
{ probeStatus = status
|
||||
, probeHeaders = []
|
||||
, probeBody = responseBody
|
||||
}
|
||||
|
||||
resolveArgs :: String -> String -> [String]
|
||||
|
|
@ -255,13 +278,13 @@ resolveArgs lane ip =
|
|||
, "--resolve", "nuthatch-" <> lane <> ":8080:" <> ip
|
||||
]
|
||||
|
||||
requireSucceededWindow :: String -> CurlResponse -> IO ()
|
||||
requireSucceededWindow :: String -> ProbeResponse -> IO ()
|
||||
requireSucceededWindow label response = do
|
||||
assertEqual (label <> " status") 200 (curlStatus response)
|
||||
assertContains label "\"result\":\"succeeded\"" (curlBody response)
|
||||
assertEqual (label <> " status") 200 (probeStatus response)
|
||||
assertContains label "\"result\":\"succeeded\"" (probeBody response)
|
||||
assertContains (label <> " window")
|
||||
"\"idempotency_window_seconds\":2"
|
||||
(curlBody response)
|
||||
(probeBody response)
|
||||
|
||||
emitRefinementTrace :: IO ()
|
||||
emitRefinementTrace =
|
||||
|
|
|
|||
Loading…
Reference in a new issue