Skip to content
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

[FormData polyfill for k6] Method body() returns an empty object for an instance of FormData class #3677

Closed
k-kudryavtseva opened this issue Apr 7, 2024 · 8 comments
Assignees
Labels
awaiting user waiting for user to respond question

Comments

@k-kudryavtseva
Copy link

k-kudryavtseva commented Apr 7, 2024

Brief summary

When trying to upload a CSV or Txt file using the polyfill, method body() returns an empty object.

k6 version

k6 v0.50.0 (go1.22.1, darwin/arm64)

OS

macOS (Version 14.3)

Docker version and image (if applicable)

No response

Steps to reproduce the problem

  1. Send a multipart POST request with a CSV or Txt file as a payload as described here.
  2. Print out the output of the body() method to the console.

`
const csvFile = open('../data/data.csv');

export function setup () {
describe("POST /", () => {

        const formData = new FormData();
        formData.append('file', http.file(csvFile, 'data.csv', 'text/csv'));

        console.log(`formData >>> ${JSON.stringify(formData)}`);
        console.log(`formData.body() >>> ${JSON.stringify(formData.body())}`);
        
        const res = http.post(`${BASE_URL}`,
            formData.body(),
            {
                headers: {
                    'Accept': '*/*',
                    'Content-Type': 'multipart/form-data; boundary=' + formData.boundary,
                }
            }
            );
        const checkPostOutput = check(res, {
            'Status is 200': (r) => r.status === 200,
        });
    });

}
`

Expected behaviour

The method returns "the assembled request body as an ArrayBuffer" as noted here. The POST request succeeded.

Actual behaviour

The method body() returns an empty object (see the screenshot). The POST request failed.
Screenshot 2024-04-07 at 00 55 49

@joanlopez
Copy link
Contributor

joanlopez commented Apr 8, 2024

Hi @k-kudryavtseva,

I might be wrong, but at first glance, I'd suggest that the behavior you're seeing, where logging the result of JSON.stringify() on an ArrayBuffer results in {}, occurs because ArrayBuffer objects do not have enumerable properties that JSON.stringify() can serialize into a JSON string.

In other words, JSON.stringify() effectively sees the ArrayBuffer as an empty object because it only serializes properties that are present on the object itself and are enumerable.

Instead, I'd suggest you to actually verify if formData.body() contains what's expected from the other side of the network (server), or by listening to the network traffic (e.g. using Wireshark or similar).

Alternatively, you could do something as below, to verify that there's something, but as the FormData contents are usually encoded as binary data, you probably won't be able to see the raw contents represented as a readable string, but something like: INFO[0000] formData.body() >>> [45,82,87,87,111,114,107....11,109,101,86,97,1045,13,10] source=console instead.

const fdBody = fd.body(); // Assuming fd.body() returns an ArrayBuffer
const typedArray = new Uint8Array(fdBody); // Create a typed array from the ArrayBuffer

// Now, you can convert this typed array to a string that can be logged.
// For example, you might convert it to a series of hexadecimal values, or directly to a string if it represents text data.
console.log(`formData.body() >>> ${JSON.stringify(Array.from(typedArray))}`);

Even simpler, you could just print the length of the ArrayBuffer with fd.body().byteLength. So, you could even see how that grows as long as you keep calling fd.append().


Please, can you confirm that's the case? Or are you actually receiving / seeing an empty payload going through network?

Thanks! 🙇🏻

@joanlopez joanlopez added question awaiting user waiting for user to respond and removed bug triage labels Apr 8, 2024
@k-kudryavtseva
Copy link
Author

Thank you so much @joanlopez for the detailed explanation. I got the output for the body() method as you described it. The issue with the failed request in my case was related to using the wrong Auth Token. Sorry for bringing up confusion and thank you again for a quick response!

@kasianovalex
Copy link

kasianovalex commented Aug 22, 2024

Greetings! @joanlopez

I encountered a similar issue and don't understand how to solve it.
Could you assist?

I have a .txt file with the following data:

Location,Account#,Invoice Number,Invoice Date,Due Date,Invoice Amt,Invoice Balance,Paid,Discount,Pay Type,Event ID,Pay ID,Paid Date,Source,DocId,ConvFee Reason,Agent ID,Email ID,Add Date
"Any","23888","1330","2024-03-18","2024-04-18","28.22",".00","10.32",".00","eCheck","","1234567","2024-07-10","","","","","email id","2024-07-10 12:00"
"Any","","1499","2024-04-09","2024-05-09","2.10",".00","25.00",".00","eCheck","","1234567","2024-07-10","","","","","email id","2024-07-10 12:00"
"Any","23887","","2024-04-09","2024-05-09","2.10",".00","1.44",".00","eCheck","","1234567","2024-07-10","","","","","email id","2024-07-10 12:00"
"Any","","","2024-05-09","2024-05-09","272.37",".00","245.60",".00","eCheck","","1234567","2024-07-10","","","","","email id","2024-07-10 12:00"

My task is to send a POST request just like the client does.

https://grafana.com/docs/k6/latest/examples/data-uploads/#advanced-multipart-request

Here’s my code:
`const txt = open("TestData.txt");

export function paymentLoadEmptyFile(fullHeaders) {
group("Uploading correct payment file", function () {
const fd = new FormData();
fd.append("text", http.file(txt, "TestData.txt", "text/plain"));

    fullHeaders["Content-Type"] = `multipart/form-data; boundary=${fd.boundary}`;
    response = http.post(
        `${baseUrl}/importFacilityFlatFile`,
        fd.body(),
        { headers: fullHeaders },
    );
});

}
`

The result is that an empty object {} is sent in the body.
image

Here is what client sends

image

@joanlopez
Copy link
Contributor

Hi @kasianovalex,

When you say "what client sends" you mean another client?
Have you tried to make sure that k6 is able to read the file (e.g. printing its contents before building the FormData)?

@kasianovalex
Copy link

@joanlopez

  1. By client i meant - browser (the second screen is related to Chrome traffic) (=
  2. Yeap, i printed and it contains all the needed lines
    image

here is my k6 version
k6.exe v0.48.0 (go1.22.4, windows/amd64)

@joanlopez
Copy link
Contributor

What if you print the fd.body() as I suggested above?

@kasianovalex
Copy link

You suggested to print file content berfore building the FormData
Here is the result:

image

@mstoykov
Copy link
Contributor

@kasianovalex Please read #3677 (comment) and follow the explaantion there on how to print the formdata body which is an ArrayBuffer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting user waiting for user to respond question
Projects
None yet
Development

No branches or pull requests

4 participants