-
Notifications
You must be signed in to change notification settings - Fork 10
Add POST request tests to validate WARC capture of request bodies #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Copilot
wants to merge
11
commits into
master
Choose a base branch
from
copilot/add-post-request-tests
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+365
−4
Open
Changes from 2 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
e1f7cff
Initial plan
Copilot e2f9479
Add POST request tests for HTTP client
Copilot 884c796
build(deps): bump the go-modules group with 2 updates (#153)
dependabot[bot] 7e3810e
fix: the value of `warcVer` changed unexpectedly (#154)
yzqzss cadb7b6
Add platform-specific memory management for macOS to spooledtempfile …
CorentinB 8541bb9
Add configurable DNS parallelization & round-robin (#156)
CorentinB abf8be2
build(deps): bump the go-modules group across 1 directory with 3 upda…
dependabot[bot] 70272b6
Add support for memory detection on Windows (#159)
NGTmeaty 5fe2448
Initial plan
Copilot 4474dcb
Use testFileSingleHashCheck in POST tests and rebase on master
Copilot 9794cb0
Merge branch 'master' into copilot/add-post-request-tests
NGTmeaty File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,11 @@ import ( | |
| "net" | ||
| "net/http" | ||
| "net/http/httptest" | ||
| "net/url" | ||
| "os" | ||
| "path" | ||
| "path/filepath" | ||
| "strconv" | ||
| "strings" | ||
| "sync" | ||
| "testing" | ||
|
|
@@ -1785,6 +1787,375 @@ func TestHTTPClientWithIPv6Disabled(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| func TestHTTPClientPOSTWithTextPayload(t *testing.T) { | ||
| var ( | ||
| rotatorSettings = defaultRotatorSettings(t) | ||
| err error | ||
| ) | ||
|
|
||
| // Create a test server that expects POST requests and echoes back the received body | ||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| if r.Method != "POST" { | ||
| t.Errorf("Expected POST request, got %s", r.Method) | ||
| w.WriteHeader(http.StatusMethodNotAllowed) | ||
| return | ||
| } | ||
|
|
||
| body, err := io.ReadAll(r.Body) | ||
| if err != nil { | ||
| t.Errorf("Failed to read request body: %v", err) | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| return | ||
| } | ||
|
|
||
| w.Header().Set("Content-Type", "text/plain") | ||
| w.WriteHeader(http.StatusOK) | ||
| w.Write([]byte("Received: ")) | ||
| w.Write(body) | ||
| })) | ||
| defer server.Close() | ||
|
|
||
| // Initialize the WARC-writing HTTP client | ||
| httpClient, err := NewWARCWritingHTTPClient(HTTPClientSettings{RotatorSettings: rotatorSettings}) | ||
| if err != nil { | ||
| t.Fatalf("Unable to init WARC writing HTTP client: %s", err) | ||
| } | ||
| waitForErrors := drainErrChan(t, httpClient.ErrChan) | ||
|
|
||
| // Create a POST request with a text payload | ||
| requestBody := strings.NewReader("Hello from POST request") | ||
| req, err := http.NewRequest("POST", server.URL, requestBody) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| req.Header.Set("Content-Type", "text/plain") | ||
|
|
||
| resp, err := httpClient.Do(req) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| io.Copy(io.Discard, resp.Body) | ||
|
|
||
| httpClient.Close() | ||
| waitForErrors() | ||
|
|
||
| files, err := filepath.Glob(rotatorSettings.OutputDirectory + "/*") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // Verify the WARC file was created | ||
| if len(files) == 0 { | ||
| t.Fatal("No WARC files were created") | ||
| } | ||
|
|
||
| // Check the WARC records contain the POST request and response | ||
| for _, path := range files { | ||
| testFileHash(t, path) | ||
|
|
||
| file, err := os.Open(path) | ||
| if err != nil { | ||
| t.Fatalf("failed to open %q: %v", path, err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| reader, err := NewReader(file) | ||
| if err != nil { | ||
| t.Fatalf("warc.NewReader failed for %q: %v", path, err) | ||
| } | ||
|
|
||
| foundRequest := false | ||
| foundResponse := false | ||
|
|
||
| for { | ||
| record, err := reader.ReadRecord() | ||
| if err != nil { | ||
| if err == io.EOF { | ||
| break | ||
| } | ||
| t.Fatalf("warc.ReadRecord failed: %v", err) | ||
| } | ||
|
|
||
| // Check for request record | ||
| if record.Header.Get("WARC-Type") == "request" { | ||
| foundRequest = true | ||
| record.Content.Seek(0, 0) | ||
| content, _ := io.ReadAll(record.Content) | ||
| contentStr := string(content) | ||
|
|
||
| // Verify it's a POST request | ||
| if !strings.Contains(contentStr, "POST") { | ||
| t.Errorf("Request record does not contain POST method") | ||
| } | ||
|
|
||
| // Verify the request body is present | ||
| if !strings.Contains(contentStr, "Hello from POST request") { | ||
| t.Errorf("Request record does not contain the expected request body") | ||
| } | ||
| } | ||
|
|
||
| // Check for response record | ||
| if record.Header.Get("WARC-Type") == "response" { | ||
| foundResponse = true | ||
| } | ||
|
|
||
| record.Content.Close() | ||
| } | ||
|
|
||
| if !foundRequest { | ||
| t.Error("No request record found in WARC file") | ||
| } | ||
| if !foundResponse { | ||
| t.Error("No response record found in WARC file") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func TestHTTPClientPOSTWithJSONPayload(t *testing.T) { | ||
| var ( | ||
| rotatorSettings = defaultRotatorSettings(t) | ||
| err error | ||
| ) | ||
|
|
||
| // Create a test server that expects POST requests with JSON | ||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| if r.Method != "POST" { | ||
| t.Errorf("Expected POST request, got %s", r.Method) | ||
| w.WriteHeader(http.StatusMethodNotAllowed) | ||
| return | ||
| } | ||
|
|
||
| if r.Header.Get("Content-Type") != "application/json" { | ||
| t.Errorf("Expected Content-Type: application/json, got %s", r.Header.Get("Content-Type")) | ||
| } | ||
|
|
||
| body, err := io.ReadAll(r.Body) | ||
| if err != nil { | ||
| t.Errorf("Failed to read request body: %v", err) | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| return | ||
| } | ||
|
|
||
| w.Header().Set("Content-Type", "application/json") | ||
| w.WriteHeader(http.StatusCreated) | ||
| w.Write([]byte(`{"status":"success","received":`)) | ||
| w.Write(body) | ||
| w.Write([]byte(`}`)) | ||
| })) | ||
| defer server.Close() | ||
|
|
||
| // Initialize the WARC-writing HTTP client | ||
| httpClient, err := NewWARCWritingHTTPClient(HTTPClientSettings{RotatorSettings: rotatorSettings}) | ||
| if err != nil { | ||
| t.Fatalf("Unable to init WARC writing HTTP client: %s", err) | ||
| } | ||
| waitForErrors := drainErrChan(t, httpClient.ErrChan) | ||
|
|
||
| // Create a POST request with a JSON payload | ||
| jsonPayload := `{"name":"test","value":123}` | ||
| requestBody := strings.NewReader(jsonPayload) | ||
| req, err := http.NewRequest("POST", server.URL, requestBody) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| req.Header.Set("Content-Type", "application/json") | ||
|
|
||
| resp, err := httpClient.Do(req) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| io.Copy(io.Discard, resp.Body) | ||
|
|
||
| httpClient.Close() | ||
| waitForErrors() | ||
|
|
||
| files, err := filepath.Glob(rotatorSettings.OutputDirectory + "/*") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // Verify the WARC file was created | ||
| if len(files) == 0 { | ||
| t.Fatal("No WARC files were created") | ||
| } | ||
|
|
||
| // Check the WARC records contain the POST request with JSON body | ||
| for _, path := range files { | ||
NGTmeaty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| testFileHash(t, path) | ||
|
|
||
| file, err := os.Open(path) | ||
| if err != nil { | ||
| t.Fatalf("failed to open %q: %v", path, err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| reader, err := NewReader(file) | ||
| if err != nil { | ||
| t.Fatalf("warc.NewReader failed for %q: %v", path, err) | ||
| } | ||
|
|
||
| foundJSONRequest := false | ||
|
|
||
| for { | ||
| record, err := reader.ReadRecord() | ||
| if err != nil { | ||
| if err == io.EOF { | ||
| break | ||
| } | ||
| t.Fatalf("warc.ReadRecord failed: %v", err) | ||
| } | ||
|
|
||
| // Check for request record | ||
| if record.Header.Get("WARC-Type") == "request" { | ||
| record.Content.Seek(0, 0) | ||
| content, _ := io.ReadAll(record.Content) | ||
| contentStr := string(content) | ||
|
|
||
| // Verify it's a POST request | ||
| if !strings.Contains(contentStr, "POST") { | ||
| t.Errorf("Request record does not contain POST method") | ||
| } | ||
|
|
||
| // Verify the JSON payload is present | ||
| if strings.Contains(contentStr, jsonPayload) { | ||
| foundJSONRequest = true | ||
| } | ||
| } | ||
|
|
||
| record.Content.Close() | ||
| } | ||
|
|
||
| if !foundJSONRequest { | ||
| t.Error("JSON payload not found in request record") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func TestHTTPClientPOSTWithFormData(t *testing.T) { | ||
| var ( | ||
| rotatorSettings = defaultRotatorSettings(t) | ||
| err error | ||
| ) | ||
|
|
||
| // Create a test server that expects POST requests with form data | ||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| if r.Method != "POST" { | ||
| t.Errorf("Expected POST request, got %s", r.Method) | ||
| w.WriteHeader(http.StatusMethodNotAllowed) | ||
| return | ||
| } | ||
|
|
||
| err := r.ParseForm() | ||
| if err != nil { | ||
| t.Errorf("Failed to parse form: %v", err) | ||
| w.WriteHeader(http.StatusBadRequest) | ||
| return | ||
| } | ||
|
|
||
| username := r.FormValue("username") | ||
| password := r.FormValue("password") | ||
|
|
||
| w.Header().Set("Content-Type", "text/plain") | ||
| w.WriteHeader(http.StatusOK) | ||
| w.Write([]byte("Login attempt for user: " + username + " (password length: " + strconv.Itoa(len(password)) + ")")) | ||
| })) | ||
| defer server.Close() | ||
|
|
||
| // Initialize the WARC-writing HTTP client | ||
| httpClient, err := NewWARCWritingHTTPClient(HTTPClientSettings{RotatorSettings: rotatorSettings}) | ||
| if err != nil { | ||
| t.Fatalf("Unable to init WARC writing HTTP client: %s", err) | ||
| } | ||
| waitForErrors := drainErrChan(t, httpClient.ErrChan) | ||
|
|
||
| // Create a POST request with form data | ||
| formData := url.Values{} | ||
| formData.Set("username", "testuser") | ||
| formData.Set("password", "testpass123") | ||
|
|
||
| req, err := http.NewRequest("POST", server.URL, strings.NewReader(formData.Encode())) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
|
|
||
| resp, err := httpClient.Do(req) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| io.Copy(io.Discard, resp.Body) | ||
|
|
||
| httpClient.Close() | ||
| waitForErrors() | ||
|
|
||
| files, err := filepath.Glob(rotatorSettings.OutputDirectory + "/*") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // Verify the WARC file was created | ||
| if len(files) == 0 { | ||
| t.Fatal("No WARC files were created") | ||
| } | ||
|
|
||
| // Check the WARC records contain the POST request with form data | ||
| for _, path := range files { | ||
| testFileHash(t, path) | ||
|
||
|
|
||
| file, err := os.Open(path) | ||
| if err != nil { | ||
| t.Fatalf("failed to open %q: %v", path, err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| reader, err := NewReader(file) | ||
| if err != nil { | ||
| t.Fatalf("warc.NewReader failed for %q: %v", path, err) | ||
| } | ||
|
|
||
| foundFormRequest := false | ||
|
|
||
| for { | ||
| record, err := reader.ReadRecord() | ||
| if err != nil { | ||
| if err == io.EOF { | ||
| break | ||
| } | ||
| t.Fatalf("warc.ReadRecord failed: %v", err) | ||
| } | ||
|
|
||
| // Check for request record | ||
| if record.Header.Get("WARC-Type") == "request" { | ||
| record.Content.Seek(0, 0) | ||
| content, _ := io.ReadAll(record.Content) | ||
| contentStr := string(content) | ||
|
|
||
| // Verify it's a POST request | ||
| if !strings.Contains(contentStr, "POST") { | ||
| t.Errorf("Request record does not contain POST method") | ||
| } | ||
|
|
||
| // Verify the form data is present (URL-encoded) | ||
| if strings.Contains(contentStr, "username=testuser") && strings.Contains(contentStr, "password=testpass123") { | ||
| foundFormRequest = true | ||
| } | ||
| } | ||
|
|
||
| record.Content.Close() | ||
| } | ||
|
|
||
| if !foundFormRequest { | ||
| t.Error("Form data not found in request record") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // MARK: Benchmarks | ||
| func BenchmarkConcurrentUnder2MB(b *testing.B) { | ||
| var ( | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.