I am trying to write a unit test to test IOException handling in some code. I thought I would be able to create an IOException by removing permissions from a file and trying to delete it. But it looks like the file gets deleted anyway. 1st question is that the expected behavior? If so it seems like a big security hole to me. Second question is anyone have a suggestion on how to create an IOException on either of the two methods Files.delete() or commons.io FileUtils.deleteDirectory(). Following is the unit test code, I have tried both Files.delete on a file and FileUtils.deleteDirectory on a directory. In the latter case I get a fileNotFound exception. The second assertion always fails. Using a debugger I stopped the code and made sure the permissions on unwriteable were 000. I am running java 11 on Redhat 7.
public void testIOException() throws IOException {
binPath.toFile().mkdirs();
Path unwriteablePath = Paths.get(binPath.toString(), "unwriteable");
Path writeablePath = Paths.get(binPath.toString(),"writeable");
File unwriteable = unwriteablePath.toFile();
unwriteable.createNewFile();
File writeable = unwriteablePath.toFile();
writeable.createNewFile();
Assertions.assertTrue(unwriteable.exists());
Assertions.assertTrue(writeable.exists());
Set<PosixFilePermission> perms =
Files.readAttributes( unwriteablePath, PosixFileAttributes.class).permissions();
//make file unwriteable
perms.remove(PosixFilePermission.OWNER_WRITE);
perms.remove(PosixFilePermission.GROUP_WRITE);
perms.remove(PosixFilePermission.OTHERS_WRITE);
perms.remove(PosixFilePermission.OWNER_READ);
perms.remove(PosixFilePermission.GROUP_READ);
perms.remove(PosixFilePermission.OTHERS_READ);
Files.setPosixFilePermissions(unwriteablePath, perms);
Assertions.assertFalse(unwriteable.canWrite());
// Deleter deleter = new Deleter(mockConfig);
// deleter.run();
try {
Files.delete(Paths.get(unwriteable.getAbsolutePath()));
} catch (IOException e) {
System.out.println("Got expected exception");
}
Assertions.assertFalse(writeable.exists());
Assertions.assertTrue(unwriteable.exists());
}
}
Related
I have a folder in my intellij project which has some .svg files, with the path "data/system/svgfiles1"
I'm doing unit testing for a method that uses these .svg files.
When I run my test locally every test is Ok.
But, in Jenkins I get an error.
The reason for this error is that I use some .svg files locally that the test needs and they are not in jenkins.
Now, the method defines a path where the data is placed. I commented where the path is defined.
As you can see, the path is hard coded.
public Optional<String> content(final Record content, final int sides) {
final Optional<String> path = Utils.findAttachmentPathById(
"./data/" + DataController.Sides[sides], // here I get the path "data/system/svgfiles1"
content.getId()
);
if (!path.isPresent()) {
return Optional.empty();
}
Optional<String> value1 = Optional.empty();
Optional<String> value2 = Optional.empty();
try {
value2 = Optional.of(FileUtils.readFileToString(new File(path.get()), StandardCharsets.UTF_8));
} catch (IOException ioException) {
logger.error("An exception", ioException);
}
try {
value1 = Optional.of(Record.format(value2.get(), content.getData()));
} catch (Exception exception) {
logger.error("An exception", exception);
}
return value1;
}
Now I created a resource folder in the tests where I added these .svg files.
The test method is this:
#Test
public void exportZipPlateSvgContentTest() {
// prepare
Record record = new Record(recordValues); // record values are only some string values
record.setId(1L);
// expected
Optional<String> expected = Optional.of(values)
// test
Optional<String> result = platesService.content(record, 1); // this is the method under test
// run
assertEquals(expected, result
}
As you can see in the test method. The path is not given as a parameter. The path is hard coded in the content method.
Since the path is hard coded in the method. Is it possible for the method to use a different path during testing?
Like, when I test it to say use the data from "test/resources/data/svgfiles1"?
I would really appreciate any input. Please let me know to clarify anything.
If you copy your files also to src/test/resources it should work.
Another approach would be to use a configuration property to specify where the files can be found and use your application.properties and application-test.properties to put in different values for production and testing.
I've been searching Google for some time now but can't seem to find any library that allows me to open password protected RAR files using Java (compressed files).
If anyone knows of one please share it with me (if possible one including a maven dependency).
I've been looking at JUnRar and java-UnRar, but both do not support password protected files for as far as I could discover.
WinRAR is shipped with two utility programs (unrar.exe and rar.exe). From Powershell, you can unrar an archive by calling: unrar e .\my-archive.rar -p[your-password]
Now, you could place this call using the exec() method of Java's Runtime class:
public class UnArchiver {
public static void main(String[] args) {
try {
String command = "unrar.exe e .\my-archive.rar -pQWERT";
Runtime.getRuntime().exec(command);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Code not tested
However, this option has some drawbacks:
Password is handled as string (bad practice when handling password)
I do not know how exec() is implemented for Windows JVMs. I think there is a risk the password ends up in an unsafe place (log file?) where it does not belong.
For me, exec() always has a smell to it (because it introduces coupling to the environment - in this case unrar.exe that is not visible on first glance for later maintainers of your code)
You introduce a platform dependency (in this case to Windows) as unrar.exe can run only on Windows (thanks #SapuSeven)
Note: When searching on Stackoverflow.com, you probably stumbled over the Junrar library. It cannot be used to extract encrypted archives (see line 122 of this file).
SevenZip library could extract many types of archive files including RAR
randomAccessFile= new RandomAccessFile(sourceZipFile, "r");
inArchive = SevenZip.openInArchive(null, // autodetect archive type
new RandomAccessFileInStream(randomAccessFile));
simpleInArchive = inArchive.getSimpleInterface();
for (int i = 0; i < inArchive.getNumberOfItems(); i++) {
ISimpleInArchiveItem archiveItem = simpleInArchive.getArchiveItem(i);
final File outFile = new File(destFolder,archiveItem.getPath());
outFile.getParentFile().mkdirs();
logger.debug(String.format("extract(%s) in progress: %s",sourceZipFile.getName(),archiveItem.getPath()));
final BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(outFile));
ExtractOperationResult result = archiveItem.extractSlow(new ISequentialOutStream() {
public int write(byte[] data) throws SevenZipException {
try {
out.write(data);
} catch (IOException e) {
throw new SevenZipException(String.format("error in writing extracted data from:%s to:%s ",sourceZipFile.getName(),outFile.getName()),e);
}finally{
try{out.close();}catch(Exception e){}
}
return data.length; // return amount of consumed data
}
});
if(result!=ExtractOperationResult.OK){
throw new SevenZipException(String.format(" %s error occured in extracting : %s item of file : %s ",result.name(),archiveItem.getPath(),sourceZipFile.getName()));
}
}
I am trying to copy a file 'project.jpg' from my /sdcard to /sdcard/temp/ folder, but for some reason , the file isn't getting copied. I am testing using a virtual device and have transferred the file 'project.jpg' via the adb shell. The function used to copy the file is,
public void $copyFile()
{
try
{
cpSrc = escapePath(this.cpSrc);
cpDest = escapePath(this.cpDest);
Log.d("$copyFile()","cpSrc = "+cpSrc);
Log.d("$copyFile()","cpDest = "+cpDest);
String destination = getFilename(cpDest,extractFilename(cpSrc));
Runtime.getRuntime().exec("dd in="+cpSrc+" of="+destination);
Log.d("$copyFile()","executed command : 'dd in="+cpSrc+" of="+destination+"'");
displayToast("File Copied Sucessfully.");
clearAllModes();
return;
}
catch(Exception e)
{
displayToast("$copyFile Error : "+e);
this.clearCopyBuffer();
clearAllModes();
}
}
where escapePath() is used to escape space characters(if any) in the given paths. I got the debug Logs as follows,
cpSrc = /sdcard/project.jpg
cpDest = /sdcard/temp
executed command : 'dd in=/sdcard/project.jpg of=/sdcard/temp/project.jpg
Could anyone point the error in the code,
BTW suggestions for other ways of coping files/folders ? it would be helpful as i am trying my hand at a file manager.
I make a POST to a request with a File included in the request body.
In my method I retrieve this File
if(request.body.file("imageFile").getOrElse(null) != null) {
request.body.file("imageFile").map{ case FilePart(key, name, contentType, content) =>
try{
val in:InputStream = new BufferedInputStream(new ByteArrayInputStream(content))
image = ImageIO.read(in)
} catch {
case e => Logger.debug(e.printStackTrace.toString); throw new Exception(e.getMessage)
}
}
}
If a File is included in the request body it tries to get it, else it just tries to get a file from S3.
else {
try{
val in:InputStream = new BufferedInputStream(new ByteArrayInputStream(S3Storage.retrieveS3File("facebook.jpg").content))
image = ImageIO.read(in)
} catch {
case e:IOException => Logger.debug("Failed to retrieve facebook image"); throw new IOException(e.getMessage)
}
All this works fine when I run it on my computer, but when I check in this and test it on the amazon server the image = ImageIO.read(in) gives me an error; Can't read input file!.
For me this makes no sense since the file is either in the request body or it's grabbed from a S3 bucket.
I've debugged this code and in the production environment there is a file available there when the "read" is done.
Why cannot the file be read from the production environment?
regards
One suggestion would be not to swallow the original exception and stack trace.
Use constructor new Exception(message, catchedException) in your catch blocks.
The filesystem AirportHDD is mounted (AFP) from the beginning and the file exists when I start this little program.
I tried to figure out the whole day why the following is not working, but couldnt find any solution:
public static void main(String[] arguments)
{
while(1==1)
{
File f=new File(
"/Volumes/AirportHDD/test/lock.csv");
System.out.println(f.exists());
AmySystem.sleep(100);
}
}
the output is:
true, true, ...
as soon as I remove the file from a different computer (AirportHDD is a mounted harddisk over network) then the output keeps saying:
true, true, ...
when I open the finder and goto this directory the output changes to: false, false, ...
when the file is added again (via another pc) the output is still:
false, false, ...
but if you open the finder again and click on the directory and finder shows the existing file, the output changes suddenly to: false, true, true, true, ...
NOTE:
also all other file operations like opening for read are failing as long as java 'thinks' the file is not there
if the program itself is creating and deleting the files then problem is not occurring
just found out while testing that with samba sharing everything is ok, but with AFP it just wont work
is there a way to tell java to do the same thing as finder, like a refresh, or do not try to cache, whatever?
I think you might be looking for the WatchService. Oracle was also kind enough to provide a tutorial.
Because the longevity of these links aren't guaranteed, I'll edit in an example code in a couple of minutes. I just wanted to let you know I think I found something in case you want to start looking at it for yourself.
UPDATE
Following the linked tutorial, I came up with code like this. I'm not sure it'll work (don't have time to test it), but it might be enough to get you started. The WatchService also has a take() method that will wait for events, which means you could potentially assume the file's existence (or lack thereof) based on the last output you gave. That will really depend on what this program will be interacting with.
If this works, good. If not, maybe we can figure out how to fix it based on whatever errors you're getting. Or maybe someone else will come along and give a better version of this code (or better option altogether) if they're more acquainted with this than I am.
public static void main(String[] arguments) {
Path path = Paths.get("/Volumes/AirportHDD/test/lock.csv");
WatchService watcher = FileSystems.getDefault().newWatchService();
WatchKey key = null;
try {
key = path.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE);
} catch (IOException x) {
System.err.println(x);
}
while(true) {//I tend to favor this infinite loop, but that's just preference.
key = watcher.poll();
if(key != null) {
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == OVERFLOW || kind == ENTRY_DELETE) {
System.out.println(false);
}
else if (kind == ENTRY_CREATE) {
System.out.println(true);
}
}//for(all events)
}//if(file event occured)
else {
File f=new File(path);
System.out.println(f.exists());
}//else(no file event occured)
AmySystem.sleep(100);
}//while(true)
}//main() method
Here is a JUnit test that shows the problem
The problem still happens using Samba on OSX Mavericks. A possible reason
is explaned by the statement in:
http://appleinsider.com/articles/13/06/11/apple-shifts-from-afp-file-sharing-to-smb2-in-os-x-109-mavericks
It aggressively caches file and folder properties and uses opportunistic locking to enable better caching of data.
Please find below a checkFile that will actually attempt to read a few bytes and forcing a true file access to avoid the caching misbehaviour ...
JUnit test:
/**
* test file exists function on Network drive
* #throws Exception
*/
#Test
public void testFileExistsOnNetworkDrive() throws Exception {
String testFileName="/Volumes/bitplan/tmp/testFileExists.txt";
File testFile=new File(testFileName);
testFile.delete();
for (int i=0;i<10;i++) {
Thread.sleep(50);
System.out.println(""+i+":"+OCRJob.checkExists(testFile));
switch (i) {
case 3:
// FileUtils.writeStringToFile(testFile, "here we go");
Runtime.getRuntime().exec("/usr/bin/ssh phobos /usr/bin/touch "+testFileName);
break;
}
}
}
checkExists source code:
/**
* check if the given file exists
* #param f
* #return true if file exists
*/
public static boolean checkExists(File f) {
try {
byte[] buffer = new byte[4];
InputStream is = new FileInputStream(f);
if (is.read(buffer) != buffer.length) {
// do something
}
is.close();
return true;
} catch (java.io.IOException fnfe) {
}
return false;
}
The problem is the network file system AFP. With the use of SAMBA everything works like expected.
Maybe the OS returns the wrong file info in OSX with the use of AFP in these scenarios.