diff options
Diffstat (limited to 'tests/httpPipeline.test')
| -rw-r--r-- | tests/httpPipeline.test | 905 |
1 files changed, 0 insertions, 905 deletions
diff --git a/tests/httpPipeline.test b/tests/httpPipeline.test deleted file mode 100644 index ef62aa3..0000000 --- a/tests/httpPipeline.test +++ /dev/null @@ -1,905 +0,0 @@ -# httpPipeline.test -# -# Test HTTP/1.1 concurrent requests including -# queueing, pipelining and retries. -# -# Copyright © 2018 Keith Nash <kjnash@users.sourceforge.net> -# -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. - -if {"::tcltest" ni [namespace children]} { - package require tcltest 2.5 - namespace import -force ::tcltest::* -} - -package require http 2.10 - -# ------------------------------------------------------------------------------ -# (0) Socket Creation in Thread, which triples the number of tests. -# ------------------------------------------------------------------------------ - -# To write a separate summary for each value of ThreadLevel, set constraint ThreadLevelSummary. -#testConstraint ThreadLevelSummary 0 - -if 0 { - # For debugging: run with a single value of ThreadLevel: 0|1|2 - set ThreadLevel 0 - testConstraint ThreadLevelSummary 1 -} -if {![info exists ThreadLevel]} { - if {[catch {package require Thread}] == 0} { - set ValueRange {0 1 2} - } else { - set ValueRange {0 1} - } - - # For each value of ThreadLevel, source this file recursively in the - # same interpreter. - foreach ThreadLevel $ValueRange { - source [info script] - } - catch {unset ThreadLevel} - catch {unset ValueRange} - if {![testConstraint ThreadLevelSummary]} { - ::tcltest::cleanupTests - } - return -} - -catch {puts "==== Test with ThreadLevel $ThreadLevel ===="} -http::config -threadlevel $ThreadLevel - -set sourcedir [file normalize [file dirname [info script]]] -source [file join $sourcedir httpTest.tcl] -source [file join $sourcedir httpTestScript.tcl] - -# ------------------------------------------------------------------------------ -# (1) Define the test scripts that will be used to generate logs for analysis - -# and also define the "correct" results. -# ------------------------------------------------------------------------------ - -proc ReturnTestScriptAndResult {ca cb delay te} { - - switch -- $ca { - 1 {set start { - START - KEEPALIVE 0 - PIPELINE 0 - }} - - 2 {set start { - START - KEEPALIVE 0 - PIPELINE 1 - }} - - 3 {set start { - START - KEEPALIVE 1 - PIPELINE 0 - }} - - 4 {set start { - START - KEEPALIVE 1 - PIPELINE 1 - }} - - default { - return -code error {no matching script} - } - } - - set middle " - [list DELAY $delay] - " - - switch -- $cb { - 1 {set end { - GET a - GET b - GET c - GET a - STOP - } - set resShort {1 ? ? ?} - set resLong {1 2 3 4} - } - - 2 {set end { - GET a - HEAD b - GET c - HEAD a - HEAD c - STOP - } - set resShort {1 ? ? ? ?} - set resLong {1 2 3 4 5} - } - - 3 {set end { - HEAD a - GET b - HEAD c - HEAD b - GET a - GET b - STOP - } - set resShort {1 ? ? ? ? ?} - set resLong {1 2 3 4 5 6} - } - - 4 {set end { - GET a - GET b - GET c - GET a - POST b address=home code=brief paid=yes - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 ? ? ? 5 ? ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 5 {set end { - POST a address=home code=brief paid=yes - POST b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - POST a address=home code=brief paid=yes - POST b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - POST a address=home code=brief paid=yes - POST b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - STOP - } - set resShort {1 2 3 4 5 6 7 8 9} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 6 {set end { - POST a address=home code=brief paid=yes - GET b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - GET a address=home code=brief paid=yes - GET b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - POST a address=home code=brief paid=yes - HEAD b address=home code=brief paid=yes - GET c address=home code=brief paid=yes - STOP - } - set resShort {1 ? 3 ? ? 6 7 ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 7 {set end { - GET b address=home code=brief paid=yes - POST a address=home code=brief paid=yes - GET a address=home code=brief paid=yes - POST c address=home code=brief paid=yes - GET b address=home code=brief paid=yes - HEAD b address=home code=brief paid=yes - POST c address=home code=brief paid=yes - POST a address=home code=brief paid=yes - GET c address=home code=brief paid=yes - STOP - } - set resShort {1 2 ? 4 ? ? 7 8 ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 8 {set end { - # Telling the server to close the connection. - GET a - GET b close=y - GET c - GET a - GET b - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 ? 3 ? ? ? ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 9 {set end { - # Telling the server to close the connection. - GET a - POST b close=y address=home code=brief paid=yes - GET c - GET a - GET b - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 2 3 ? ? ? ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 10 {set end { - # Telling the server to close the connection. - GET a - GET b close=y - POST c address=home code=brief paid=yes - GET a - GET b - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 ? 3 ? ? ? ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 11 {set end { - # Telling the server to close the connection twice. - GET a - GET b close=y - GET c - GET a - GET b close=y - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 ? 3 ? ? 6 ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 12 {set end { - # Telling the server to delay before sending the response. - GET a - GET b delay=1 - GET c - GET a - GET b - STOP - } - set resShort {1 ? ? ? ?} - set resLong {1 2 3 4 5} - } - - 13 {set end { - # Making the server close the connection (time out). - GET a - WAIT 2000 - GET b - GET c - GET a - GET b - STOP - } - set resShort {1 2 ? ? ?} - set resLong {1 2 3 4 5} - } - - 14 {set end { - # Making the server close the connection (time out) twice. - GET a - WAIT 2000 - GET b - GET c - GET a - WAIT 2000 - GET b - GET c - GET a - GET b - GET c - STOP - } - set resShort {1 2 ? ? 5 ? ? ? ?} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 15 {set end { - POST a address=home code=brief paid=yes - POST b address=home code=brief paid=yes close=y delay=1 - POST c address=home code=brief paid=yes delay=1 - POST a address=home code=brief paid=yes close=y - WAIT 2000 - POST b address=home code=brief paid=yes delay=1 - POST c address=home code=brief paid=yes close=y - POST a address=home code=brief paid=yes - POST b address=home code=brief paid=yes close=y - POST c address=home code=brief paid=yes - STOP - } - set resShort {1 2 3 4 5 6 7 8 9} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 16 {set end { - POST a address=home code=brief paid=yes - GET b address=home code=brief paid=yes - POST c address=home code=brief paid=yes close=y - GET a address=home code=brief paid=yes - GET b address=home code=brief paid=yes close=y - POST c address=home code=brief paid=yes - WAIT 2000 - POST a address=home code=brief paid=yes - HEAD b address=home code=brief paid=yes close=y - GET c address=home code=brief paid=yes - STOP - } - set resShort {1 ? 3 4 ? 6 7 ? 9} - set resLong {1 2 3 4 5 6 7 8 9} - } - - 17 {set end { - GET b address=home code=brief paid=yes - POST a address=home code=brief paid=yes - GET a address=home code=brief paid=yes - POST c address=home code=brief paid=yes close=y - GET b address=home code=brief paid=yes - HEAD b address=home code=brief paid=yes close=y - POST c address=home code=brief paid=yes - WAIT 2000 - POST a address=home code=brief paid=yes - WAIT 2000 - GET c address=home code=brief paid=yes - STOP - } - set resShort {1 2 3 4 5 ? 7 8 9} - set resLong {1 2 3 4 5 6 7 8 9} - } - - - 18 {set end { - REPOST 0 - GET a - WAIT 2000 - POST b address=home code=brief paid=yes - GET c - GET a - STOP - } - set resShort {1 2 ? ?} - set resLong {1 2 3 4} - # resShort is overwritten below for the case ($te == 1). - } - - - 19 {set end { - REPOST 0 - GET a - WAIT 2000 - GET b address=home code=brief paid=yes - GET c - GET a - STOP - } - set resShort {1 2 ? ?} - set resLong {1 2 3 4} - } - - - 20 {set end { - POSTFRESH 1 - GET a - WAIT 2000 - POST b address=home code=brief paid=yes - GET c - GET a - STOP - } - set resShort {1 3 ?} - set resLong {1 3 4} - } - - - 21 {set end { - POSTFRESH 1 - GET a - WAIT 2000 - GET b address=home code=brief paid=yes - GET c - GET a - STOP - } - set resShort {1 2 ? ?} - set resLong {1 2 3 4} - } - - 22 {set end { - GET a - WAIT 2000 - KEEPALIVE 0 - POST b address=home code=brief paid=yes - KEEPALIVE 1 - GET c - GET a - STOP - } - set resShort {1 3 ?} - set resLong {1 3 4} - } - - - 23 {set end { - GET a - WAIT 2000 - KEEPALIVE 0 - GET b address=home code=brief paid=yes - KEEPALIVE 1 - GET c - GET a - STOP - } - set resShort {1 3 ?} - set resLong {1 3 4} - } - - 24 {set end { - GET a - KEEPALIVE 0 - POST b address=home code=brief paid=yes - KEEPALIVE 1 - GET c - GET a - STOP - } - set resShort {1 ? ?} - set resLong {1 3 4} - } - - - 25 {set end { - GET a - KEEPALIVE 0 - GET b address=home code=brief paid=yes - KEEPALIVE 1 - GET c - GET a - STOP - } - set resShort {1 ? ?} - set resLong {1 3 4} - } - - default { - return -code error {no matching script} - } - } - - - if {$ca < 3} { - # Not Keep-Alive. - set result "Passed all sanity checks." - - } elseif {$ca == 3} { - # Keep-Alive, not pipelined. - set result {} - append result "Passed all sanity checks.\n" - append result "Have overlaps including response body:\n" - - } else { - # Keep-Alive, pipelined: ($ca == 4) - set result {} - append result "Passed all sanity checks.\n" - append result "Overlap-free without response body:\n" - append result "$resShort" - } - - # - The special case of test *.18*-testEof needs test results to be - # individually written. - # - These test -repost 0 when there is a POST to apply it to, and the server - # timeout has not been detected. - if {($cb == 18) && ($te == 1)} { - if {$ca < 3} { - # Not Keep-Alive. - set result "Passed all sanity checks." - - } elseif {$ca == 3 && $delay == 0} { - # Keep-Alive, not pipelined. - set result [MakeMessage { - |Problems with sanity checks: - |Wrong sequence for token ::http::2 - {A B C D X X X} - |- and error(s) X - |Wrong sequence for token ::http::3 - {A X X} - |- and error(s) X - |Wrong sequence for token ::http::4 - {A X X X} - |- and error(s) X - | - |Have overlaps including response body: - | - }] - - } elseif {$ca == 3} { - # Keep-Alive, not pipelined. - set result [MakeMessage { - |Problems with sanity checks: - |Wrong sequence for token ::http::2 - {A B C D X X X} - |- and error(s) X - | - |Have overlaps including response body: - | - }] - - } elseif {$delay == 0} { - # Keep-Alive, pipelined: ($ca == 4) - set result [MakeMessage { - |Problems with sanity checks: - |Wrong sequence for token ::http::2 - {A B C D X X X} - |- and error(s) X - |Wrong sequence for token ::http::3 - {A X X} - |- and error(s) X - |Wrong sequence for token ::http::4 - {A X X X} - |- and error(s) X - | - |Overlap-free without response body: - | - }] - - } else { - set result [MakeMessage { - |Problems with sanity checks: - |Wrong sequence for token ::http::2 - {A B C D X X X} - |- and error(s) X - | - |Overlap-free without response body: - | - }] - - } - } - - return [list "$start$middle$end" $result] -} - -# ------------------------------------------------------------------------------ -# Proc MakeMessage -# ------------------------------------------------------------------------------ -# WHD's one-line command to generate multi-line strings from readable code. -# -# Example: -# set blurb [MakeMessage { -# |This command allows multi-line strings to be created with readable -# |code, and without breaking the rules for indentation. -# | -# |The command shifts the entire block of text to the left, omitting -# |the pipe character and the spaces to its left. -# }] -# ------------------------------------------------------------------------------ - -proc MakeMessage {in} { - regsub -all -line {^\s*\|} [string trim $in] {} - # N.B. Implicit Return. -} - - -proc ReturnTestScript {ca cb delay te} { - lassign [ReturnTestScriptAndResult $ca $cb $delay $te] script result - return $script -} - -proc ReturnTestResult {ca cb delay te} { - lassign [ReturnTestScriptAndResult $ca $cb $delay $te] script result - return $result -} - - -# ------------------------------------------------------------------------------ -# (2) Command to run a test script and use httpTest to analyse the logs. -# ------------------------------------------------------------------------------ - -namespace import httpTestScript::runHttpTestScript -namespace import httpTestScript::cleanupHttpTestScript -namespace import httpTest::cleanupHttpTest -namespace import httpTest::logAnalyse -namespace import httpTest::setHttpTestOptions - -proc RunTest {header footer delay te} { - set num [runHttpTestScript [ReturnTestScript $header $footer $delay $te]] - set skipOverlaps 0 - set notPiped {} - set notIncluded {} - - # -------------------------------------------------------------------------- - # Custom code for specific tests - # -------------------------------------------------------------------------- - if {$header < 3} { - set skipOverlaps 1 - for {set i 1} {$i <= $num} {incr i} { - lappend notPiped $i - } - } elseif {$header > 2 && $footer == 18 && $te == 1} { - set skipOverlaps 1 - if {$delay == 0} { - # Transaction 1 is conventional. - # Check that transactions 2,3,4 are cancelled. - set notPiped {1} - set notIncluded $notPiped - } else { - # Transaction 1 is conventional. - # Check that transaction 2 is cancelled. - # The timing of transactions 3 and 4 is uncertain. - set notPiped {1 3 4} - set notIncluded $notPiped - } - } elseif {$footer in {20 22 23 24 25}} { - # Transaction 2 uses its own socket. - set notPiped 2 - set notIncluded $notPiped - } else { - } - # -------------------------------------------------------------------------- - # End of custom code for specific tests - # -------------------------------------------------------------------------- - - - set Results [logAnalyse $num $skipOverlaps $notIncluded $notPiped] - lassign $Results msg cleanE cleanF dirtyE dirtyF - if {$msg eq {}} { - set msg "Passed all sanity checks." - } else { - set msg "Problems with sanity checks:\n$msg" - } - - if 0 { - puts $msg - puts "Overlap-free including response body:\n$cleanF" - puts "Have overlaps including response body:\n$dirtyF" - puts "Overlap-free without response body:\n$cleanE" - puts "Have overlaps without response body:\n$dirtyE" - } - - if {$header < 3} { - # No ordering, just check that transactions all finish - set result $msg - } elseif {$header == 3} { - # Not pipelined - check overlaps with response body. - set result "$msg\nHave overlaps including response body:\n$dirtyF" - } else { - # Pipelined - check overlaps without response body. Check that the - # first request, the first requests after replay, and POSTs are clean. - set result "$msg\nOverlap-free without response body:\n$cleanE" - } - set ::nTokens $num - return $result -} - - -# ------------------------------------------------------------------------------ -# (3) VERBOSITY CONTROL -# ------------------------------------------------------------------------------ -# If tests fail, run an individual test with -verbose 1 or 2 for diagnosis. -# If still obscure, uncomment #Log and ##Log lines in the http package. -# ------------------------------------------------------------------------------ - -setHttpTestOptions -verbose 0 - -# ------------------------------------------------------------------------------ -# (4) Define the base URLs used for testing. Each must have a query string. -# ------------------------------------------------------------------------------ -# - A HTTP/1.1 server is required. It should be configured to provide -# persistent connections when requested to do so, and to close these -# connections if they are idle for one second. -# - The resource must be served with status 200 in response to a valid GET or -# POST. -# - The value of "page" is always specified in the query-string. Different -# resources for the three values of "page" allow testing of both chunked and -# unchunked transfer encoding. -# - The variables "close" and "delay" may be specified in the query-string (for -# a GET) or the request body (for a POST). -# - "delay" is a numerical value in seconds, and causes the server to delay -# the response, including headers. -# - "close", if it has the value "y", instructs the server to close the -# connection ater the current request. -# - Any other variables should be ignored. -# ------------------------------------------------------------------------------ - -namespace eval ::httpTestScript { - variable URL - array set URL { - a http://test-tcl-http.kerlin.org/index.html?page=privacy - b http://test-tcl-http.kerlin.org/index.html?page=conditions - c http://test-tcl-http.kerlin.org/index.html?page=welcome - } -} - - -# ------------------------------------------------------------------------------ -# (5) Define the tests -# ------------------------------------------------------------------------------ -# Constraints: -# - serverNeeded - the URLs defined at (4) must be available, and must have the -# properties specified there. -# - duplicate - the value of -pipeline does not matter if -keepalive 0 -# - timeout1s - tests that work correctly only if the server closes -# persistent connections after one second. -# -# Server timeout of persistent connections should be 1s. Delays of 2s are -# intended to cause timeout. -# Servers are usually configured to use a longer timeout: this will cause the -# tests to fail. The "2000" could be replaced with a larger number, but the -# tests will then be inconveniently slow. -# ------------------------------------------------------------------------------ - -#testConstraint serverNeeded 1 -#testConstraint timeout1s 1 -#testConstraint duplicate 1 - -# ------------------------------------------------------------------------------ -# Proc SetTestEof - to edit the command ::http::KeepSocket -# ------------------------------------------------------------------------------ -# The usual line in command ::http::KeepSocket is " set TEST_EOF 0". -# Whether the value set in the file is 0 or 1, change it here to the value -# specified by the argument. -# -# It is worth doing all tests for both values of the argument. -# -# test 0 - ::http::KeepSocket is unchanged, detects server eof where possible -# and closes the connection. -# test 1 - ::http::KeepSocket is edited, does not detect server eof, so the -# reaction to finding server eof can be tested without the difficulty -# of testing in the few milliseconds of an asynchronous close event. -# ------------------------------------------------------------------------------ - -proc SetTestEof {test} { - set body [info body ::http::KeepSocket] - set subs " set TEST_EOF $test" - set count [regsub -line -all -- {^\s*set TEST_EOF .*$} $body $subs newBody] - if {$count != 1} { - return -code error {proc ::http::KeepSocket has unexpected form} - } - proc ::http::KeepSocket {token} $newBody - return -} - -for {set header 1} {$header <= 4} {incr header} { - if {$header == 4} { - setHttpTestOptions -dotted 1 - set match glob - } else { - setHttpTestOptions -dotted 0 - set match exact - } - - if {$header == 2} { - set cons0 {serverNeeded duplicate} - } else { - set cons0 serverNeeded - } - - for {set footer 1} {$footer <= 25} {incr footer} { - foreach {delay label} { - 0 a - 1 b - 2 c - 3 d - 5 e - 8 f - 12 g - 100 h - 500 i - 2000 j - } { - foreach te {0 1} { - if {$te} { - set tag testEof - } else { - set tag normal - } - set suffix {} - set cons $cons0 - - # ------------------------------------------------------------------ - # Custom code for individual tests - # ------------------------------------------------------------------ - if {$footer in {18}} { - # Custom code: - if {($label eq "j") && ($te == 1)} { - continue - } - if {$te == 1} { - # The test (of REPOST 0) is useful if tag is "testEof" - # (server timeout without client reaction). The same test - # has a different result if tag is "normal". - - set suffix " - extra test for -repost 0 - ::http::2 must be" - append suffix " cancelled" - if {($delay == 0)} { - append suffix ", along with ::http::3 ::http::4 if" - append suffix " the test creates these before ::http::2" - append suffix " is cancelled" - } - } else { - } - } elseif {$footer in {19}} { - set suffix " - extra test for -repost 0" - } elseif {$footer in {20 21}} { - set suffix " - extra test for -postfresh 1" - if {($footer == 20)} { - append suffix " - ::http::2 uses a separate socket" - append suffix ", other requests use a persistent connection" - } - } elseif {$footer in {22 23 24 25}} { - append suffix " - ::http::2 uses a separate socket" - append suffix ", other requests use a persistent connection" - } else { - } - - if {($footer >= 13 && $footer <= 23)} { - # Test use WAIT and depend on server timeout before this time. - lappend cons timeout1s - } - # ------------------------------------------------------------------ - # End of custom code. - # ------------------------------------------------------------------ - - set name "pipeline test header $header footer $footer delay $delay $tag$suffix" - - - # Here's the test: - test httpPipeline-${header}.${footer}${label}-${tag}-$ThreadLevel $name \ - -constraints $cons \ - -setup [string map [list TE $te] { - # Restore default values for tests: - http::config -pipeline 1 -postfresh 0 -repost 1 - http::init - set http::http(uid) 0 - SetTestEof {TE} - }] -body [list RunTest $header $footer $delay $te] -cleanup { - # Restore default values for tests: - http::config -pipeline 1 -postfresh 0 -repost 1 - cleanupHttpTestScript - SetTestEof 0 - cleanupHttpTest - after 2000 - # Wait for persistent sockets on the server to time out. - } -result [ReturnTestResult $header $footer $delay $te] -match $match - - - } - - } - } -} - -# ------------------------------------------------------------------------------ -# (*) Notes on tests *.18*-testEof, *.19*-testEof - these test -repost 0 -# ------------------------------------------------------------------------------ -# These tests are a bit awkward because the main test kit analyses whether all -# requests are satisfied, with retries if necessary, and it has result analysis -# for processing retry logs. -# - *.18*-testEof tests that certain requests are NOT satisfied, so the analysis -# is a one-off. -# - Tests *.18a-testEof depend on client/server timing - the test needs to call -# http::geturl for all requests before the POST (request 2) is cancelled. -# We test that requests 2, 3, 4 are all cancelled. -# - Other tests *.18*-testEof may not request 3 and 4 in time for the to be -# added to the write queue before request 2 is completed. We simply check that -# request 2 is cancelled. -# - The behaviour is different if all connections are allowed to time out -# (label "j"). This case is not needed to test -repost 0, and is omitted. -# - Tests *.18*-normal and *.19* are conventional (-repost 0 should have no -# effect). -# ------------------------------------------------------------------------------ - - -unset header footer delay label suffix match cons name te -namespace delete ::httpTest -namespace delete ::httpTestScript - -if {[testConstraint ThreadLevelSummary]} { - ::tcltest::cleanupTests -} |
