I am using selenium and testng to do Web UI automation test. I download files with Firefox using the same way as Access to file download dialog in Firefox. The file will be downloaded with default name without Open/Save/Cancel dialog successfully.
I repeat the test for different test data. The problems are
When there is a file with 'abc.pdf' in target 'browser.download.dir', if I download a file with same name, the new file will be saved to 'abc (1).pdf'; that's not what I want. In the following test I have problem to decide to open which pdf and check its content.
(Now my solution is, write a retry method: check if the file is downloaded, if yes, move it to another folder; if no, check again. Is there a better way?)
Sometimes when I click link or button to download, the file name is generated dynamically by web system. The file could be .pdf, .eml, .txt, etc. I can know the file suffix from UI. But I can't know the name in advance. Same here, I need open the file and do assertion in following test.
How to overcome? What if I need run the test in multiple threads? Much appreciated!
An easy way is to wait for a new file to be created with a file watcher:
https://docs.oracle.com/javase/tutorial/essential/io/notification.html
This is an example to wait for a .pdf file to be created:
// wait for the PDF to be downloaded
File file = WaitForNewFile(download_folder, ".pdf", 100);
/**
* Waits for a new file to be downloaded with a file watcher
*/
public static File WaitForNewFile(Path folder, String extension, int timeout_sec) throws InterruptedException, IOException {
long end_time = System.currentTimeMillis() + timeout_sec * 1000;
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
folder.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
for (WatchKey key; null != (key = watcher.poll(end_time - System.currentTimeMillis(), TimeUnit.MILLISECONDS)); key.reset()) {
for (WatchEvent<?> event : key.pollEvents()) {
File file = folder.resolve(((WatchEvent<Path>)event).context()).toFile();
if (file.toString().toLowerCase().endsWith(extension.toLowerCase()))
return file;
}
}
}
return null;
}
Related
I have a problem with saving files and then downloading them after generating a .war file.
I need to handle the generation of many files after pressing the button by admin in the application. The files are generated using part of the code that was sent using the POST method and second part is from the database.
The files are hundreds / thousands and it is impossible to do it manually. Admin generates files from time to time. The user should be able to download these files from the application.
When I run the application in IntelliJ, app has access to the folders on the disk, so the following code works:
(part of backend class, responfible for saving files in path)
private void saveTextToFile(String text, String fileName) {
String filePathAndName = "/static/myFiles/" + fileName+ ".txt";
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(".").getFile() + filePathAndName );
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(file);
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print(text);
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
The file was saved in folder:
C:\Users...\myProject\target\classes\static.
(and this is link to generated file in thymeleaf)
<html xmlns:th="http://www.thymeleaf.org">
<a th:href="#{|/myFiles/${thisIsMyFileName}|}">Download file</a>
</html>
Unfortunately, when I generate the .war file and run it, the files are not saved in the application's "resources" folder. As a result, the user cannot download this file via the link generated by thymeleaf.
In general, you do not want to upload anything into your application's files - it opens you to many security problems if someone figures out how to overwrite parts of the application, and in most application servers, it is simply not writable.
A much better approach is to have a designated server folder where you can write things. For example, you could have the following in your configuration:
myapp.base-folder = /any/server/folder/you/want
And then, in the code, you would find that folder as follows:
// env is an #AutoWired private Environment
File baseFolder = new File(env.getProperty("myapp.base-folder"));
I find this better than using a database (as #Stultuske suggested in comments), because databases are great for relations, but mostly overkill for actual files. Files can be accessed externally without firing up the database with minimal hassle, and having them separate keeps your database much easier to backup.
To generate links to the file, simply create a link as you would to any other type of request
<a th:href="#{/file/${fileId}|}">Download file</a>
-- and to handle it in the server, but returning the contents of the file:
#GetMapping(value="/file/{id}")
public StreamingResponseBody getFile(#PathVariable long id) throws IOException {
File f = new File(baseFolder, ""+id); // numerical id prevents filesytem traversal
InputStream in;
if (f.exists()) {
in = new BufferedInputStream(new FileInputStream(f));
} else {
// you could also signal error by returning a 404
in = new BufferedInputStream(getClass().getClassLoader()
.getResourceAsStream("static/img/unknown-id.jpg"));
}
return new StreamingResponseBody() {
#Override
public void writeTo(OutputStream os) throws IOException {
FileCopyUtils.copy(in, os);
}
};
}
I prefer numerical IDs to avoid hassles with path traversal - but you can easily use string filenames instead, and deal with security issues by carefully checking that the canonical path of the requested file starts with the canonical path of your baseFolder
So I am uploading all files from a dir into S3 using TransferManager
and I am able to upload also .
But my issue in the same dir file are getting written also.
So how do i call that method to write into S3 .
Do i have to call that method on fixed interval ?
Please suggest what could be the best way to call that method.
public void uploadDir(Path strFile,String strFileName){
ArrayList<File> files = new ArrayList<File>();
for (Path path : strFile) {
files.add(new File(path.toString()));
}
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
MultipleFileUpload xfer = xfer_mgr.uploadFileList(bucketName,strFileName, new File("."), files);
//XferMgrProgress.showTransferProgress(xfer);
//XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
System.err.println(e.getErrorMessage());
System.exit(1);
}
}
Couple of solutions, you could try any, based on your need.
Solution 1:- For scanrio like your, instead of time interval, you should be using fileAge.
FileAge:when the file was last modified, this common concept used by file Poller either local directory or remote directory.
So think like your files takes max. 20 seconds in writing, then only pull files older then 20s or more.
Solution 2:-
Other way is ask your clients, the program generating files to use some extension say .tmp, when file writing completed, ask them to convert it to actual file extension and modify your program to skip files with extension .tmp.
e.g While writing abc.jpg to abc.jpg.tmp, when files writing completed, then rename it to abc.jpg.
Hope this helps.
My program has a folder called data - which stores text files- when i click save in my JAR application though nothing happens. How can i make it so i can access and save new files? Here is some of the code
public void saveAs() {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Routine"); fileChooser.setInitialDirectory(new File("data/routines"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("txt", "*.txt"));
if (fileName != null) {
fileChooser.setInitialFileName(fileName);
}
save(fileChooser.showSaveDialog(stage));
}
I also did it with a absolute path and that did not work either
Without seeing your save(java.io.File) method, I can't say. FileChooser.showSaveDialog just shows the dialog and tells you what file they chose (if any). You then have to write it whether it's a JAR or txt.
Try this:
private void save(File where){
if(where==null){ //they canceled.
return;
}
try(OutputStream out = Files.newOutputStream(where.toPath())){
//Write to out.
}
}
You can write things into JAR files with the plain JarFile constructor, but it looks like you want plain text files. Although you may be able to update your application's JAR files while it's running, most programs don't do that because it's odd.
I'm trying to build some automated test for a mailbox application and I'm trying to attach a file. I've read all the documentation from previous post and was able to come up with this:
public void I_attach_a_file_that_exceeds_the_limit() throws Throwable {
WebElement attachFile = driver.findElement(By.id("attachment"));
File f = new File("C:\\coop-provider-swm-specs\\src\\test\\resources\\attachments\\20481kb.txt");
attachFile.sendKeys(f.getCanonicalPath());
}
The problem with this is that the file that it attaches is not the real file. The file that is attached is blank (not sure how that works). The file that I need to attach is a big file and I need to do this in order the authenticate that the user does not exceed the limit for attachments that is allowed.
Change:
attachFile.sendKeys(f.getCanonicalPath());
To:
attachFile.sendKeys(f.getCanonicalPath()).submit();
I am currently working on an application, where users are given an option to browse and upload excel file, I am badly stuck to get the absolute path of the file being browsed. As location could be anything (Windows/Linux).
import org.apache.myfaces.custom.fileupload.UploadedFile;
-----
-----
private UploadedFile inpFile;
-----
getters and setters
public UploadedFile getInpFile() {
return inpFile;
}
#Override
public void setInpFile(final UploadedFile inpFile) {
this.inpFile = inpFile;
}
we are using jsf 2.0 for UI development and Tomahawk library for browse button.
Sample code for browse button
t:inputFileUpload id="file" value="#{sampleInterface.inpFile}"
valueChangeListener="#{sampleInterface.inpFile}" />
Sample code for upload button
<t:commandButton action="#{sampleInterface.readExcelFile}" id="upload" value="upload"></t:commandButton>
Logic here
Browse button -> user will select the file by browsing the location
Upload button -> on Clicking upload button, it will trigger a method readExcelFile in SampleInterface.
SampleInterface Implementation File
public void readExcelFile() throws IOException {
System.out.println("File name: " + inpFile.getName());
String prefix = FilenameUtils.getBaseName(inpFile.getName());
String suffix = FilenameUtils.getExtension(inpFile.getName());
...rest of the code
......
}
File name : abc.xls
prefix : abc
suffix: xls
Please help me in getting the full path ( as in c:.....) of the file being browsed, this absolute path would then be passed to excelapachepoi class where it will get parsed and contents would be displayed/stored in ArrayList.
Why do you need the absolute file path? What can you do with this information? Creating a File? Sorry no, that is absolutely not possible if the webserver runs at a physically different machine than the webbrowser. Think once again about it. Even more, a proper webbrowser doesn't send information about the absolute file path back.
You just need to create the File based on the uploaded file's content which the client has already sent.
String prefix = FilenameUtils.getBaseName(inpFile.getName());
String suffix = FilenameUtils.getExtension(inpFile.getName());
File file = File.createTempFile(prefix + "-", "." + suffix, "/path/to/uploads");
InputStream input = inpFile.getInputStream();
OutputStream output = new FileOutputStream(file);
try {
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(input);
}
// Now you can use File.
See also:
How to get the file path from HTML input form in Firefox 3
I remember to have some problem with this in the past too. If I am not mistaken, I think you cannot get the full file path when uploading a file. I think the browser won't tell you it for security purposes.