Skip to content

Commit

Permalink
Adding SharedFileInputStream tests
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos committed Mar 25, 2024
1 parent f4684d5 commit 3336cbb
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 23 deletions.
42 changes: 22 additions & 20 deletions api/src/main/java/jakarta/mail/util/SharedFileInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class SharedFileInputStream extends BufferedInputStream
*/
static class SharedFile implements AutoCloseable {
private int cnt;
private RandomAccessFile in;
RandomAccessFile in;

SharedFile(String file) throws IOException {
this.in = new RandomAccessFile(file, "r");
Expand Down Expand Up @@ -256,10 +256,10 @@ private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
if (false) {
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, do not bother to copy the
bytes into the local buffer. In this way buffered streams will
cascade harmlessly. */
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, do not bother to copy the
bytes into the local buffer. In this way buffered streams will
cascade harmlessly. */
if (len >= buf.length && markpos < 0) {
// XXX - seek, update bufpos - how?
return in.read(b, off, len);
Expand Down Expand Up @@ -328,10 +328,10 @@ public synchronized long skip(long n) throws IOException {

if (avail <= 0) {
// If no mark position set then don't keep in buffer
/*
/*
if (markpos <0)
return in.skip(n);
*/
*/

// Fill in buffer to save bytes for reset
fill();
Expand Down Expand Up @@ -424,6 +424,8 @@ public boolean markSupported() {
*/
@Override
public void close() throws IOException {
if (in == null)
return;
sf.close();
sf = null;
in = null;
Expand All @@ -439,7 +441,7 @@ public void close() throws IOException {
@Override
public long getPosition() {
//System.out.println("getPosition: start " + start + " pos " + pos
// + " bufpos " + bufpos + " = " + (bufpos + pos - start));
// + " bufpos " + bufpos + " = " + (bufpos + pos - start));
if (in == null)
throw new RuntimeException("Stream closed");
return bufpos + pos - start;
Expand Down Expand Up @@ -473,18 +475,18 @@ public synchronized InputStream newStream(long start, long end) {
// for testing...
/*
public static void main(String[] argv) throws Exception {
SharedFileInputStream is = new SharedFileInputStream(argv[0]);
java.util.Random r = new java.util.Random();
int b;
while ((b = is.read()) >= 0) {
System.out.write(b);
if (r.nextDouble() < 0.3) {
InputStream is2 = is.newStream(is.getPosition(), -1);
int b2;
while ((b2 = is2.read()) >= 0)
;
}
}
SharedFileInputStream is = new SharedFileInputStream(argv[0]);
java.util.Random r = new java.util.Random();
int b;
while ((b = is.read()) >= 0) {
System.out.write(b);
if (r.nextDouble() < 0.3) {
InputStream is2 = is.newStream(is.getPosition(), -1);
int b2;
while ((b2 = is2.read()) >= 0)
;
}
}
}
*/
}
104 changes: 101 additions & 3 deletions api/src/test/java/jakarta/mail/util/SharedFileInputStreamTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -16,13 +16,22 @@

package jakarta.mail.util;

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import jakarta.mail.util.SharedFileInputStream.SharedFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;
import java.util.concurrent.TimeoutException;

import static org.junit.Assert.fail;
import org.junit.Test;

/**
* Please note:
Expand Down Expand Up @@ -62,4 +71,93 @@ public void testGrandChild() throws Exception {
file.delete();
}
}

@Test
public void testCloseMultipleTimes() throws Exception {
File file = new File(SharedFileInputStreamTest.class.getResource("/jakarta/mail/util/sharedinputstream.txt").toURI());
SharedFileInputStream in = new SharedFileInputStream(file);
in.close();
in.close();
}

@Test
public void testOpenIfOneOpened() throws Exception {
File file = new File(SharedFileInputStreamTest.class.getResource("/jakarta/mail/util/sharedinputstream.txt").toURI());
SharedFileInputStream in0 = null;
SharedFileInputStream in1 = null;
try (SharedFileInputStream in = new SharedFileInputStream(file)) {
in0 = (SharedFileInputStream) in.newStream(0, 6);
in1 = (SharedFileInputStream) in.newStream(6, 12);
}
RandomAccessFile ra0 = getRandomAccessFile(in0);
RandomAccessFile ra1 = getRandomAccessFile(in1);
// It is the same instance
assertEquals(ra0, ra1);
// RandomAccessFile still be open
in1.close();
assertEquals(false, isClosed(ra1));
in0.close();
// All SharedFileInputStream are closed, so RandomAccessFile gets closed too
assertEquals(true, isClosed(ra1));
}

@Test
public void testGC() throws Exception {
File file = new File(SharedFileInputStreamTest.class.getResource("/jakarta/mail/util/sharedinputstream.txt").toURI());
SharedFileInputStream in = new SharedFileInputStream(file);
GCUtil gcUtil = new GCUtil(in);
SharedFileInputStream in0 = (SharedFileInputStream) in.newStream(0, 6);
in.close();
in = null;
gcUtil.waitTillGCed(1000);
gcUtil = new GCUtil(in0);
SharedFileInputStream in1 = (SharedFileInputStream) in0.newStream(6, 12);
assertEquals("test0\n", new String(in0.readAllBytes()));
in0.close();
in0 = null;
gcUtil.waitTillGCed(1000);
assertEquals("test1\n", new String(in1.readAllBytes()));
in1.close();
}

private RandomAccessFile getRandomAccessFile(SharedFileInputStream in) throws Exception {
Field f1 = SharedFileInputStream.class.getDeclaredField("sf");
f1.setAccessible(true);
SharedFile rin = (SharedFile) f1.get(in);
RandomAccessFile rf = rin.in;
return rf;
}

private boolean isClosed(RandomAccessFile rf) throws Exception {
try {
rf.readByte();
return false;
} catch (IOException e) {
return true;
}
}

private static class GCUtil {

private final ReferenceQueue<Object> rq = new ReferenceQueue<>();
private final PhantomReference<Object> phantomRef;

private GCUtil(Object ref) {
phantomRef = new PhantomReference<>(ref, rq);
}

private void waitTillGCed(long timeout) throws Exception {
Reference<? extends Object> gced;
long time = 0;
long sleep = 100;
while ((gced = rq.poll()) != phantomRef) {
Thread.sleep(sleep);
time = time + sleep;
if (time >= timeout) {
throw new TimeoutException("Instance not GCed after " + timeout + " millis");
}
System.gc();
}
}
}
}
10 changes: 10 additions & 0 deletions api/src/test/resources/jakarta/mail/util/sharedinputstream.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
test0
test1
test2
test3
test4
test5
test6
test7
test8
test9
1 change: 1 addition & 0 deletions copyright-exclude
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mail/src/test/resources/jakarta/mail/internet/paramdata
mail/src/test/resources/jakarta/mail/internet/paramdatanostrict
api/src/test/resources/jakarta/mail/internet/tokenlist
api/src/test/resources/jakarta/mail/internet/addrlist
api/src/test/resources/jakarta/mail/util/sharedinputstream.txt
mail/src/test/resources/jakarta/mail/internet/MailDateFormat_old.ser
mail/src/test/resources/jakarta/mail/internet/MailDateFormat_new.ser
mail/src/test/resources/com/sun/mail/test/keystore.jks
Expand Down

0 comments on commit 3336cbb

Please sign in to comment.