How to read a file for mulipart file upload from separate features in another location?- Karate DSL - file-upload

To be brief with the requirement:
My folder structure looks as below:
Requirement & Challenge: When I try to read the FixedTestFile.dat
from different features, the read method appends the path wrong followed by the path of feature file and hence fails.
Tried with the following ways to read the file but failed with error.
And multipart file myFile = { read: 'src/test/java/e2e/common/data/FixedTestFile.dat', filename: #(randomFileName), contentType: 'text/plain' }
Logs:
Requirement: I have to read file "FixedTestFile.dat" from different features located in folders individual and testScenarios while using in Mutlipart file myFile.
Note : I tried with using classpath: and file: But no luck
And multipart file myFile = { read: 'classpath:e2e/common/data/FixedTestFile.dat', filename: #(randomFileName), contentType: 'text/plain' }
Tried using a variable for filename with path and tried using this as a parameter in read. Did not work.
* string myDataFileWithPath = "\'"+"../common/data/"+fileName+".dat"+"\'"
And multipart file myFile = { read: myDataFileWithPath, filename: #(randomFileName), contentType: 'text/plain' }
So the question is: "How to read a file from two features in another location?" Precisely for a multipart file upload.
Am I missing something or it is a bug while reading files?

Related

Correct media type for swagger spec for downloading zip file

I am creating an api which allows downloading a zip file, so for this I am looking for correct media type for sending this zip file as response in swagger "2.0" specification.
My current api spec looks like this
/config:
get:
produces:
- application/zip
responses:
200: # OK
description: All config files
schema:
type: string
format: binary
I have compiled this spec with "go-swagger" and implemented the backend for this, but when try to call this API I get this error
http: panic serving 127.0.0.1:20366: applicationZip producer has not yet been implemented
In the documentation of swagger I don't see this media type
Official swagger media types
So then what should be the correct media type if we want to provide an API to download a zip file.
Thanks in advance
You need to implement this.
The error occurs because of the following generated code:
func NewSampleAPI(spec *loads.Document) *SampleAPI {
return &SampleAPI{
...
ApplicationZipProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error {
return errors.NotImplemented("applicationZip producer has not yet been implemented")
}),
So after calling NewSampleAPI, you should set ApplicationZipProducer:
api := operations.NewSampleAPI(swaggerSpec)
api.ApplicationZipProducer = func(w io.Writer, data interface{}) error {
...
}
You should use "application/octet-stream" for implementing api that downloads file as an attachment , and since its Producer is already implemented by default so you won't face this issue.
As mentioned in other answer, using "application/octet-stream" partially solves the issue, but the browser does not know the file format. I think that his can be improved adding the correct headers to the response, that will tell the browser that the file has a zip extension. At least, I can download a file as ZIP and Firefox recognizes it.
#Operation(summary = "Downloads a ZIP file)
#GetMapping(value = "/zip", produces="application/octet-stream")
public byte[] start(HttpServletResponse response) {
final ContentDisposition contentDisposition = ContentDisposition.builder("attachment")
.filename("MyFile.zip").build();
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
return getZipDataAsByteArray();
}

How do I upload multiple files with multipart in Karate

I would like to upload multiple image files in one request using multipart. I have reviewed the Karate examples on this, but the multiple file upload does not meet my need (/multiple endpoint here - https://github.com/intuit/karate/blob/master/karate-demo/src/main/java/com/intuit/karate/demo/controller/UploadController.java). My service method (Spring REST) signature expects an array of MultipartFile[] so that I can accept any number of files. Here is my scenario:
Scenario: Upload multiple files
* def json = {}
* set json.files[0] = { read: 'file1.jpg', filename: 'file1.jpg', contentType: 'image/jpeg' }
* set json.files[1] = { read: 'file2.jpg', filename: 'file2.jpg', contentType: 'image/jpeg' }
Given path '/rest'
And multipart files json
When method post
Then status 200
And here is the Spring web service method (just trying to receive the files right now, so the method doesn't do much):
#PostMapping("/rest")
public String handleFileUpload(#RequestParam("file") MultipartFile[] file) {
System.out.println("Len: " + file.length);
for(MultipartFile currentFile : file) {
System.out.println("In here: " + currentFile.getOriginalFilename());
}
return file[0].getOriginalFilename();
}
When I run this I receive a Karate error: 'multipart file value should be json'
If I change the scenario to do this:
Scenario: Upload multiple files
* def json = {}
* set json.files = { read: 'file1.jpg', filename: 'file1.jpg', contentType: 'image/jpeg' }, { read: 'file2.jpg', filename: 'file2.jpg', contentType: 'image/jpeg' }
Given path '/rest'
And multipart files json
When method post
Then status 200
Then the test executes ok, but only one file ends up in the MultipartFile array 'files' (service method argument).
What is the proper way to upload multiple files to the web service method above using Karate?
Edit: Adding client code (below) and updated Spring method above.
Here is a simple HTML form that will submit multiple files to the Spring method above:
<form method="POST" enctype="multipart/form-data" action="/rest">
<table>
<tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
<tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
</table>
</form>
When submitted I get 2 files in the service method.
Seems that it does work, you just need to send the same parameter twice in the feature file
And multipart file files = { read: 'mergeTest.pdf', filename: 'upload-name.pdf', contentType: 'application/pdf' }
And multipart file files = { read: 'mergeTest.pdf', filename: 'upload-name.pdf', contentType: 'application/pdf' }
And multipart field filesMetadata = .........................................
my service:
public ResponseEntity<StreamingResponseBody> mergePdfs(#RequestPart #Validated
List<FileMetaData> filesMetadata, #RequestPart #Validated List<MultipartFile> files)
Wow, never seen this before and it is likely that Karate does not support it. I'm also wondering if this is legal as per the HTTP spec - as far as I know - each file has to have unique field-name. Do you have the corresponding client-side code for the Apache HTTP Client, that would help.
EDIT: also see answer by Esteban Lopez below: https://stackoverflow.com/a/59833358/143475
Your best bet may be to submit a feature request and also contribute code to expedite. Note that this is the first time in 2 years that anyone has reported this as a problem.

Uploading file to BrickFTP using Dropzone

I have been trying to implement file upload to BrickFTP using Dropzone, but the uploaded file won't open because it contains the WebKitFormBoundary at the top of the file content.
I'm putting method as PUT in Dropzone configuration as per BrickFTP's documentation. BrickFTP uses Amazon S3 so the files are actually being uploaded to S3. I did everything as per their documentation, and everything worked except this last problem I'm having with those extra information at the top of the uploaded file content.
Here is the Coffeescript code responsible for file upload:
brickFTPData = {}
# As per BrickFTP docs, step 1 is
# to get the dedicated upload url for each file by sending a
# request to REST API to indicate intent to upload a file
getUploadUri = (file) ->
result = ""
$.ajax
url : '/a/portal-dev/get-api-keys'
type : 'POST'
dataType : 'json'
data : { file_name: file.name }
async : false
success : (data, textStatus, jqXHR) ->
brickFTPData[file.upload.uuid] =
file_name : file.name
upload_uri : data.upload_uri
ref : data.ref
result = data.upload_uri
return result
# 3rd step is to notify the REST API that the file upload is complete.
finishUpload = (file) ->
$.ajax
url : '/a/portal-dev/upload-done'
type : 'POST'
dataType : 'json'
data :
ref : brickFTPData[file.upload.uuid].ref
file_name : brickFTPData[file.upload.uuid].file_name
success : (data) ->
delete brickFTPData[file.upload.uuid]
console.log data.status
# 2nd step is to upload the file
sampleQuoteDropzone = new Dropzone "#sampleQuoteDropzone",
url : '/demo'
method : 'PUT'
headers : {"Content-Type": "application/octet-stream"}
success : (file, request) ->
finishUpload(file)
sampleQuoteDropzone.on 'processing', (file) ->
upload_uri = getUploadUri(file)
sampleQuoteDropzone.options.url = upload_uri
Upload works fine using the above code but as said when I open the uploaded file into a text editor it starts with following code:
------WebKitFormBoundaryw4bIakMBbkp7ES2E
Content-Disposition: form-data; name="file"; filename="IMG_5652.jpg"
Content-Type: image/jpeg
If I delete these lines and save the file it will work.
But this problem is not seen when uploading file using a regular ajax call outside Dropzone. Following is the working code:
$.ajax
url: data.upload_uri
type: 'PUT'
contentType: 'application/octet-stream'
data: file
processData: false
success: (response) ->
finishUpload(file, data)
Can anyone please advise how to solve this problem?
I solved the problem with following code:
sampleQuoteDropzone.on 'sending', (data, xhr, formData) ->
_send = xhr.send
xhr.send = ->
_send.call(xhr, data)
This solution was actually found here. I saw this before posting this question here, but wasn't sure if this is the right problem/solution. I contacted BrickFTP and they responded fairly quickly saying this solution may work for me, and yes it certainly does.

SAPUI5 upload file and use it as model

I would like to upload a xml file from the local workspace and use it as model. I can upload files to the server but i don't know how to retrieve the data from the uploaded object and set or load it to my model
Here is how I m uploading the file.
jQuery.ajax({
url: oFileUploader.getUploadUrl(),
headers: oHeaders,
type: 'PUT',
cache: false,
contentType: false,
processData: false,
data: file
});
}
I could not use the standard oFileUploader.upload() because it uses the http method "POST" and I wanted to do a "PUT"
Thank you
It is not clear how you get the contents of the file variable that you are passing to the jQuery.ajax call. Depending on this, you have three options hat come to mind:
Directly use the file variable contents in a model.
Use the FileReader API to read the file contents and put them in a model.
Make the back-end service return the XML content of the file as a response to the AJAX call and then store the response in a model.

File upload checking REAL file mime type when uploading directly to S3

I'm using DropzoneJS to upload files directly to S3. When they add I file I am using my backend to check the mime type and create the S3 signature. When I say adding I file, I just means it's added it to the Dropzone queue so the file isn't uploaded yet it's just sending metadata about the file to the /upload/sign url.
this.on('addedfile', function (file) {
$.get('/upload/sign', {
name: file.name,
size: file.size,
type: file.type,
}).done(function (response) {
myDropzone.options.url = response.attributes.action;
file.additionalData = response.additionalData;
myDropzone.processFile(file);
}).fail(function (response) {
var data = JSON.parse(response.responseText);
myDropzone.emit('error', file, data);
});
});
This is all good! The problem is the file's mime type is only determined by the file extension, so I can happily rename a file from image.jpg to image.mp3 and file.type will be audio/mp3. This I guess is fine for browser warnings, but not if I want that mp3 to play or if I eventually want to process the audio!
Is there any way of telling the REAL mime type of the file, without having to pass the upload directly to the servers file system? I need to upload directly to S3 so passing it through an EC2 is not an option.