artillery
artillery copied to clipboard
TypeError: Method get TypedArray.prototype.length called on incompatible receiver [object Object] or indefinite hang when trying to modify requestParams.body
I'm trying to upload a file via a PUT request with no luck. As far as I can tell this is the way that it is being done in artillery-plugin-http-file-uploads. I suspect the TypeError is coming from when either artillery or request is trying to calculate the length of the request body. Is this a known issue? Has anyone been able to successfully upload a file using artillery?
artillery-plugin-http-file-uploads/index.js:
traverse(requestParams).forEach(function(o) {
if (o && o.fromFile) {
const filename = path.resolve(
basePath,
renderVariables(o.fromFile, userContext.vars));
debug(`Updating`, o, `with`, filename);
const stream = fs.createReadStream(filename);
// in-place update:
this.update(stream);
}
});
app.ts:
import { config } from "./config";
import * as artillery from "./node_modules/artillery/lib/commands/run";
import * as fs from "fs";
import * as temp from "tmp";
let script = {
"config": {
"target": "http://" + config.get("pasUrl") + ":" + config.get("pasPort"),
"phases": [
{
"duration": 1,
"arrivalCount": 1
}
],
"processor": "../scenarios/scenario1.js",
"mode": "uniform"
},
"scenarios": [
{
"flow": [
{
"post": {
"url": "/ViewingSession",
"headers": {
"Content-Type": "application/json"
},
"beforeRequest": "setRequestBodyForViewingSessionPost",
"capture": {
"json": "$.viewingSessionId",
"as": "viewingSessionId"
}
}
},
{
"put": {
"url": "/ViewingSession/u{{ viewingSessionId }}/SourceFile",
"headers": {
"Accusoft-Secret": "mysecretkey",
"Content-Type": "application/octet-stream"
},
"beforeRequest": "setRequestBodyForViewingSessionPut",
}
}
]
}
]
};
let tempfile = temp.fileSync({ "dir": "temp" });
fs.writeFileSync(tempfile.name, JSON.stringify(script, undefined, 4), { "flag": "w" });
// artillery(filename, options)
artillery(tempfile.name, {});
scenario1.ts:
export function setRequestBodyForViewingSessionPut(requestParams, context, ee, next) {
requestParams.body = fs.createReadStream(path.join(__dirname, "..", "documents", "creating-wireframes.pdf"));
return next(); // Artillery hangs indefinetly
}
export function setRequestBodyForViewingSessionPut2(requestParams, context, ee, next) {
let readStream = fs.createReadStream(path.join(__dirname, "..", "documents", "creating-wireframes.pdf"));
let bufferArray = [];
readStream.on("data", function(data) {
bufferArray.push(data);
});
readStream.on("close", function() {
requestParams.body = Buffer.concat(bufferArray);
return next(); // TypeError: Method get TypedArray.prototype.length called on incompatible receiver [object Object]
});
}
requestParams.body = fs.readFileSync(path.join(__dirname, "..", "documents", "creating-wireframes.pdf"));
also yields the error:
TypeError: Method get TypedArray.prototype.length called on incompatible receiver [object Object]
@brianjenkins94 file uploads are known to work well. There's a DIY solution here: https://github.com/shoreditch-ops/artillery/issues/320#issuecomment-329448748. If you need a solution which just works out of the box, and also works when running distributed tests from AWS, check out Artillery Pro.
Looks like #320 is sending Content-Type: multipart/form-data
. I'm looking to send Content-Type: application/octet-stream
.
Which version of Artillery are you running?
"artillery": "^1.6.0-19"
Looks like artillery is using 'got' by Sindre Sorhus as its request library.
Artillery doesn't expose that to the hook so we can't change how we upload a file. Ideally we could stream it, but that would require piping a stream to the request
instance here:
https://github.com/artilleryio/artillery/blob/main/packages/core/lib/engine_http.js#L668
Look at the docs for got: https://github.com/sindresorhus/got/blob/HEAD/documentation/3-streams.md
Specifically this:
// For POST, PUT, PATCH, and DELETE methods, `got.stream` returns a `stream.Writable`.
// This example POSTs the contents of a file to a URL.
await streamPipeline(
fs.createReadStream('index.html'),
got.stream.post('https://sindresorhus.com'),
new stream.PassThrough()
);
So we can't stream an upload from artillery without changes to support passing a stream and piping it to the got request.
Since this issue has been idle for a long time, I'm guessing this isn't an in-demand feature.