JMeter - Read Image from Data file for PUT Request - image

I have a csv data as
FirstName,MiddleName,LastName,ImageLocation
Jack|Michel|Rechards|C:\Image\picture.jpg
Tom|Peter|Kim|C:\Image\picture123.jpg
I'm trying to configure Jmeter to read above data file and pass image as form-data to REST API PUT resource as form-data. API accepts image as ByteBuffer.
In JMeter, multipart/form-data upload is only available for POST but not for PUT resource.
For Image, I have written a code in BeanShell PreProcessor that puts byte[] in a variable
String imageLoc = vars.get("ImageLocation");
File file = new File(imageLoc);
byte[] buffer = new byte[(int) file.length()];
InputStream ios = null;
try {
ios = new FileInputStream(file);
if (ios.read(buffer) == -1) {
throw new IOException(
"EOF reached while trying to read the whole file");
}
} finally {
try {
if (ios != null)
ios.close();
} catch (IOException e) {
}
}
vars.put("imageData", new String(buffer));
and the variable imageData is passed in HTTP request body data as
------=_parttest
Content-Type: image/jpeg; name=test.jpeg
Content-Transfer-Encoding: binary
Content-Disposition: form-data; name="Picture"; filename="test.jpeg"
${imageData}
------=_parttest--
For some reason, images are not rendered correctly for requests from Jmeter. If I make similar postman PUT request to API to save image and make another GET request to read image, it's read successfully.
Either I have not configured my test correctly(beanShell code issue or HTTP Request body data issue) or there is a better way to configure this test for reading images from path in data file and pass image as form-data to API PUT resource.
Looking forward to experts advice.

It is actually possible to perform a multipart PUT request using JMeter, you will need to:
Add a HTTP Header Manager and configure it to send Content-Type header with the value of:
multipart/related; boundary=parttest
Construct your request body in the HTTP Request using the same boundary value as in the Content-Type header
See Testing REST API File Uploads in JMeter for example test plan which updates a document in Google Drive using PUT request, you can use it as a reference.
Also I would rather suggest using __FileToString() function in order to read the image file contents or if you prefer scripting - go for JSR223 PreProcessor and Groovy language instead.

Related

Is there a way to map local in proxyman based off of parameters attached to the body of a url?

I have a url:
https://cn.company.com/appv2/search
and want to have a different map local depending on the request coming with a different parameter in the body (i.e. it is NOT attached to the url like https://cn.company.com/appv2/search?cursor=abc. Instead it is in the body of the request { cursor: abc }.
Any idea on if this can be done in proxyman?
I basically want to be able to stub pagination through the proxy without waiting on a server implementation. So I'd have no cursor on the first request, server would return a cursor and then use that on the next request and get a different response from server on the request so that I can test out the full pagination flow.
Yes, it can be solved with the Scripting from Proxyman app.
Use Scripting to get the value of the request body
If it's matched, use Scripting to mimic the Map Local (Mock API also supports)
Here is the sample code and how to do it:
Firstly, call your request and make sure you can see the HTTPS Response
Right-Click on the request -> Tools -> Scripting
Select the Mock API checkbox if you'd like a Mock API
Use this code
/// This func is called if the Response Checkbox is Enabled. You can modify the Response Data here before it goes to the client
/// e.g. Add/Update/Remove: headers, statusCode, comment, color and body (json, plain-text, base64 encoded string)
///
async function onResponse(context, url, request, response) {
// get the value from the body request
var cursorValue = request.body["cursor"];
// Use if to provide a map local file
if (cursorValue === "abc") {
// Set Content Type as a JSON
response.headers["Content-Type"] = "application/json";
// Set a Map Local File
response.bodyFilePath = "~/Desktop/my_response_A.json";
} else if (cursorValue === "def") {
// Set Content Type as a JSON
response.headers["Content-Type"] = "application/json";
// Set a Map Local File
response.bodyFilePath = "~/Desktop/my_response_B.json";
}
// Done
return response;
}
Reference
Map Local with Scripting: https://docs.proxyman.io/scripting/snippet-code#map-a-local-file-to-responses-body-like-map-local-tool-proxyman-2.25.0+

POST a single large file in .net core

I have a .net core 2.1 api application that will download a file from a remote location based on the file name. Here is the code:
static public class FileDownloadAsync
{
static public async Task DownloadFile(string filename)
{
//File name is 1GB.zip for testing
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
using (HttpClient client = new HttpClient())
{
string url = #"http://speedtest.tele2.net/" + filename;
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (Stream readFrom = await response.Content.ReadAsStreamAsync())
{
string tempFile = $"D:\\Test\\{filename}";
using (Stream writeTo = File.Open(tempFile, FileMode.Create))
{
await readFrom.CopyToAsync(writeTo);
}
}
stopwatch.Stop();
Debug.Print(stopwatch.Elapsed.ToString());
}
}
}
This is working great, it will pull a 1 gig file down in about 50 seconds. Well within the required download time. I have hard coded a test file to download in this code for testing as well as storage location--these values will ultimately come from a config file when moved into production. Here is the API endpoint that calls this function:
[HttpGet("{fileName}")]
public async Task<string> GetFile(string fileName)
{
await FileDownloadAsync.DownloadFile(fileName);
return "Done";
}
So getting the file from a remote location down to the local server is not a problem. I need some help/guidance on re-posting this file to another API. Once the file is downloaded, there is some work done on the file to prepare it for upload (the files are all MP4 files), and once that work is done, I need to post it to another API for more proprietary processing. Here is the API end point data I have:
POST: /batch/requests Allocates resources to start new batch transcription. Use this method to request[work] on the input
audio data. Upon the accepted request, the response provides
information about the associated request ID and processing status.
Headers: Authorization: Authorization token
Accept: application/json
Content-Type: Indicates the audio format. The value must be:
audio/x-wav;codec=pcm;bit=16;rate=8000;channels=1
audio/x-wav;codec=pcm;bit=16;rate=16000;channels=1
audio/x-raw;codec=pcm;bit=16;rate=8000;channels=1
audio/x-raw;codec=pcm;bit=16;rate=16000;channels=1
video/mp4
Content-Length (optional): The size of the input voice file. Not
required if a chunked transfer is used.
Query string parameters (required):
profileId: one of supported (see GET profiles) customerId: the id of
the customer. A string of minimum 1 and up to 250 alphanumeric, dot
(.) and dash (-) characters.
So I will set the Content-Type to video/MP4 for processing. Note that if the input size is not used if a chunked transfer is used.
Right now, I am more concerned with just posting (streaming) the file in a non-chunked format while we await for more information on what they consider "chunking" a file.
So I am looking for help on steaming the file from disk to the endpoint. Everything I am running across for .net core API is creating the API to download the file from a POST like a Razor page or Angular page--I already have that. I just need some help on "re-posting" to another API.
Thanks
Using the HttpClient you open a stream to the file, create a content stream, set the necessary headers and post to the endpoint
Stream file = File.Open(filepath, FileMode.Open);
var content = new StreamContent(file);
content.Headers.ContentType = new MediaTypeHeaderValue("video/MP4");
client.DefaultRequestHeaders.Add("Authorization", "token here");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json");
using (HttpResponseMessage response = await client.PostAsync(url, content)) {
//...
}

Capture current JSF page content

I want to capture the current page and send it to an application that converts it to pdf.
This is what I am using:
FacesContext facesContext=FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)
facesContext.getExternalContext().getResponse();
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
// RequestPrinter.debugString();
response.reset();
// download a pdf file
response.setContentType("application/pdf");
response.setHeader("Content-Disposition","attachment;filename="+new Date().toString()+".pdf");
prince.setVerbose(true);
prince.setLog(logFile);
try{
//getPath() to the page the user is currently on
URL pagePath=new URL(this.getPath());
URLConnection urlConnection = pagePath.openConnection();
urlConnection.setDoOutput(true);
int length = urlConnection.getContentLength();
//Lets use inputStream
BufferedInputStream bis=new BufferedInputStream(urlConnection.getInputStream());
response.setContentLength(length);
//this.getPageUsingJSoup().data().getBytes();
//call prince and pass params for inputstream outputStream
prince.convert(bis,response.getOutputStream());
urlConnection.getInputStream().close();
}catch(MalformedURLException mu){
mu.printStackTrace();
}
catch(IOException ioe){
ioe.printStackTrace();
}
facesContext.responseComplete();
Since the website requires authentication, the pdf generated is the loging error page.
Is there a way to capture the page's content that uses the current user's session?
Thank you in advance.
Just request the page in the same HTTP session as the current request. If your webapp supports URL rewriting (as by default), then just append session ID as jsessionid path fragment:
String sessionId = ((HttpSession) externalContext.getSession()).getId();
InputStream input = new URL("http://localhost:8080/context/page.jsf;jsessionid=" + sessionId).openStream();
// ...
Or if your webapp doesn't accept URL rewriting, but accepts cookies only, then set it as a request cookie the usual way:
URLConnection connection = new URL("http://localhost:8080/context/page.jsf").openConnection();
connection.setRequestProperty("Cookie", "JSESSIONID=" + sessionId);
InputStream input = connection.getInputStream();
// ...
Note that I removed setDoOutput() since you don't seem to be interested in performing a POST request.
I do not know how to capture the page's content using the current user's session, but I can suggest another way to do it - you could move the pdf conversion logic inside a Selenium test-case and use the test-case to navigate and login to the page requiring authentication. After the automated tc has logged in, you could call your pdf conversion logic...?
Yes of course there is. You are sending this content, so you have it. You should store the Content Object. If you dont have it, inspect your byte streams. The content should be there ;)
There of couple of websites which allow you to convert the entire page to pdf and save it as .pdf file. Try out the site http://pdfcrowd.com/ Hope this helps you.

how to get a httppostedfile from a ASP.NET Web API (POST or PUT) call?

Actually my question is short.
How can I get a HttpPostedFile from a ASP.NET Web API POST or PUT?
I did see that I can get various information from the Request like Request.Header, Request.Content, Request.Properties. Where in there can I find the file I passed and how can I create a HttpPostedFile from it?
Thanks in advance!
Check out the great article from Henrik Nielsen to post multi-part content (i.e posting a form with file)
UPDATE: Add simple code for a controller to receive a file without multipart content
If you only need your controller to receive a file (i.e. no multipart content), you could do something like the above. The request only contains the file binary and the filename is passed within the URL.
public Task<HttpResponseMessage> Post([FromUri]string filename)
{
Guid uploadedFile = Guid.NewGuid();
Task<HttpResponseMessage> task = Request.Content.ReadAsStreamAsync().ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
throw new HttpResponseException(HttpStatusCode.InternalServerError);
try
{
using (Stream stream = t.Result)
{
//TODO: Write the stream to file system / db as you need
}
}
catch (Exception e)
{
Object o = e;
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.GetBaseException().Message);
}
return Request.CreateResponse(HttpStatusCode.Created, uploadedFile.ToString());
});
return task;
}
Your short question does not have a short answer I am afraid.
ASP.NET Web API exposes you to the wonders of HTTP while ASP.NET MVC abstracted some of it - in this case for HttpPostedFile.
So a bit of background:
HTTP posts where a file is involved usually has multipart form data content. This means that you are mixing different kind of content-type: your normal form data will be sent using formurlencoded while the files will be sent application/octent-stream.
So in Web API, all you have to do is to say
var contents = message.Content.ReadAsMultipartAsync(); // message is HttpRequestMessage
One of the contents will contain your file.

JAX-RS : When we send back an image, in which format is it received by the client?

I have the following code to send images to the client :
#GET
#Path("/images/{image}") #Produces("image/*")
public Response getImage(#PathParam("image") String image) {
File f = new File(image);
if (!f.exists()) {
throw new WebApplicationException(404);
}
String mt = new MimetypesFileTypeMap().getContentType(f);
return Response.ok(f, mt).build();
}
Now, the client will receive the image in which format ? Will it be wrapped in XML, or as raw binary ? If I simply put the response in the src of an image tag, will the image be rendered ?
If not, how can I make the raw binary stream that is returned, into an image that can be placed in an img tag
ad 1) File will be serialized as raw binary (opened stream will be directly returned)
ad 2) you mean location of the resource which is returning image as a file, right? if so, then the answer is yes (you can't just put raw binary data into html page like "<img src="<binary_data>" />)
You can also add content type to your response header e.g. image/jpeg , image/png or image/gif so that the client can decide for himself as to what is the type of image by reading the response header.
One more thing if the url you are posting to is returning image stream there is no need for an ajax request. If its a servlet you can jsut add the servlet url to image src, and it'll work.

Resources