1 /*
   2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 4434723 4482726 4559072 4795550 5081340 5103988 6984545
  26  * @summary Test FileChannel.transferFrom and transferTo (use -Dseed=X to set PRNG seed)
  27  * @library ..
  28  * @library /test/lib
  29  * @build jdk.test.lib.RandomFactory
  30  * @run testng/timeout=300 Transfer
  31  * @key randomness
  32  */
  33 
  34 import java.io.BufferedReader;
  35 import java.io.File;
  36 import java.io.FileInputStream;
  37 import java.io.FileOutputStream;
  38 import java.io.InputStreamReader;
  39 import java.io.IOException;
  40 import java.io.RandomAccessFile;
  41 import java.io.Reader;
  42 import java.net.InetAddress;
  43 import java.net.InetSocketAddress;
  44 import java.nio.ByteBuffer;
  45 import java.nio.channels.FileChannel;
  46 import java.nio.channels.NonReadableChannelException;
  47 import java.nio.channels.Pipe;
  48 import java.nio.channels.ServerSocketChannel;
  49 import java.nio.channels.SocketChannel;
  50 import java.nio.channels.spi.SelectorProvider;
  51 import java.util.Random;
  52 import java.util.concurrent.TimeUnit;
  53 
  54 import jdk.test.lib.RandomFactory;
  55 
  56 import org.testng.annotations.Test;
  57 
  58 public class Transfer {
  59 
  60     private static Random generator = RandomFactory.getRandom();
  61 
  62     @Test
  63     public void testFileChannel() throws Exception {
  64         File source = File.createTempFile("source", null);
  65         source.deleteOnExit();
  66         File sink = File.createTempFile("sink", null);
  67         sink.deleteOnExit();
  68 
  69         FileOutputStream fos = new FileOutputStream(source);
  70         FileChannel sourceChannel = fos.getChannel();
  71         sourceChannel.write(ByteBuffer.wrap(
  72             "Use the source, Luke!".getBytes()));
  73         sourceChannel.close();
  74 
  75         FileInputStream fis = new FileInputStream(source);
  76         sourceChannel = fis.getChannel();
  77 
  78         RandomAccessFile raf = new RandomAccessFile(sink, "rw");
  79         FileChannel sinkChannel = raf.getChannel();
  80         long oldSinkPosition = sinkChannel.position();
  81         long oldSourcePosition = sourceChannel.position();
  82 
  83         long bytesWritten = sinkChannel.transferFrom(sourceChannel, 0, 10);
  84         if (bytesWritten != 10)
  85             throw new RuntimeException("Transfer failed");
  86 
  87         if (sourceChannel.position() == oldSourcePosition)
  88             throw new RuntimeException("Source position didn't change");
  89 
  90         if (sinkChannel.position() != oldSinkPosition)
  91             throw new RuntimeException("Sink position changed");
  92 
  93         if (sinkChannel.size() != 10)
  94             throw new RuntimeException("Unexpected sink size");
  95 
  96         bytesWritten = sinkChannel.transferFrom(sourceChannel, 1000, 10);
  97 
  98         if (bytesWritten > 0)
  99             throw new RuntimeException("Wrote past file size");
 100 
 101         sourceChannel.close();
 102         sinkChannel.close();
 103 
 104         source.delete();
 105         sink.delete();
 106     }
 107 
 108     @Test
 109     public void testReadableByteChannel() throws Exception {
 110         int[] testSizes = { 0, 10, 1023, 1024, 1025, 2047, 2048, 2049 };
 111 
 112         for (int size : testSizes) {
 113             SelectorProvider sp = SelectorProvider.provider();
 114             Pipe p = sp.openPipe();
 115             Pipe.SinkChannel sink = p.sink();
 116             Pipe.SourceChannel source = p.source();
 117             sink.configureBlocking(false);
 118 
 119             ByteBuffer outgoingdata = ByteBuffer.allocateDirect(size + 10);
 120             byte[] someBytes = new byte[size + 10];
 121             generator.nextBytes(someBytes);
 122             outgoingdata.put(someBytes);
 123             outgoingdata.flip();
 124 
 125             int totalWritten = 0;
 126             while (totalWritten < size + 10) {
 127                 int written = sink.write(outgoingdata);
 128                 if (written < 0)
 129                     throw new Exception("Write failed");
 130                 totalWritten += written;
 131             }
 132 
 133             File f = File.createTempFile("blah"+size, null);
 134             f.deleteOnExit();
 135             RandomAccessFile raf = new RandomAccessFile(f, "rw");
 136             FileChannel fc = raf.getChannel();
 137             long oldPosition = fc.position();
 138 
 139             long bytesWritten = fc.transferFrom(source, 0, size);
 140             fc.force(true);
 141             if (bytesWritten != size)
 142                 throw new RuntimeException("Transfer failed");
 143 
 144             if (fc.position() != oldPosition)
 145                 throw new RuntimeException("Position changed");
 146 
 147             if (fc.size() != size)
 148                 throw new RuntimeException("Unexpected sink size "+ fc.size());
 149 
 150             fc.close();
 151             sink.close();
 152             source.close();
 153 
 154             f.delete();
 155         }
 156     }
 157 
 158     @Test
 159     public void xferTest02() throws Exception { // for bug 4482726
 160         byte[] srcData = new byte[5000];
 161         for (int i=0; i<5000; i++)
 162             srcData[i] = (byte)generator.nextInt();
 163 
 164         // get filechannel for the source file.
 165         File source = File.createTempFile("source", null);
 166         source.deleteOnExit();
 167         RandomAccessFile raf1 = new RandomAccessFile(source, "rw");
 168         FileChannel fc1 = raf1.getChannel();
 169 
 170         // write out data to the file channel
 171         long bytesWritten = 0;
 172         while (bytesWritten < 5000) {
 173             bytesWritten = fc1.write(ByteBuffer.wrap(srcData));
 174         }
 175 
 176         // get filechannel for the dst file.
 177         File dest = File.createTempFile("dest", null);
 178         dest.deleteOnExit();
 179         RandomAccessFile raf2 = new RandomAccessFile(dest, "rw");
 180         FileChannel fc2 = raf2.getChannel();
 181 
 182         int bytesToWrite = 3000;
 183         int startPosition = 1000;
 184 
 185         bytesWritten = fc1.transferTo(startPosition, bytesToWrite, fc2);
 186 
 187         fc1.close();
 188         fc2.close();
 189         raf1.close();
 190         raf2.close();
 191 
 192         source.delete();
 193         dest.delete();
 194     }
 195 
 196     @Test
 197     public void xferTest03() throws Exception { // for bug 4559072
 198         byte[] srcData = new byte[] {1,2,3,4} ;
 199 
 200         // get filechannel for the source file.
 201         File source = File.createTempFile("source", null);
 202         source.deleteOnExit();
 203         RandomAccessFile raf1 = new RandomAccessFile(source, "rw");
 204         FileChannel fc1 = raf1.getChannel();
 205         fc1.truncate(0);
 206 
 207         // write out data to the file channel
 208         int bytesWritten = 0;
 209         while (bytesWritten < 4) {
 210             bytesWritten = fc1.write(ByteBuffer.wrap(srcData));
 211         }
 212 
 213         // get filechannel for the dst file.
 214         File dest = File.createTempFile("dest", null);
 215         dest.deleteOnExit();
 216         RandomAccessFile raf2 = new RandomAccessFile(dest, "rw");
 217         FileChannel fc2 = raf2.getChannel();
 218         fc2.truncate(0);
 219 
 220         fc1.transferTo(0, srcData.length + 1, fc2);
 221 
 222         if (fc2.size() > 4)
 223             throw new Exception("xferTest03 failed");
 224 
 225         fc1.close();
 226         fc2.close();
 227         raf1.close();
 228         raf2.close();
 229 
 230         source.delete();
 231         dest.delete();
 232     }
 233 
 234     // xferTest04() and xferTest05() moved to Transfer4GBFile.java
 235 
 236     static void checkFileData(File file, String expected) throws Exception {
 237         FileInputStream fis = new FileInputStream(file);
 238         Reader r = new BufferedReader(new InputStreamReader(fis, "ASCII"));
 239         StringBuilder sb = new StringBuilder();
 240         int c;
 241         while ((c = r.read()) != -1)
 242             sb.append((char)c);
 243         String contents = sb.toString();
 244         if (! contents.equals(expected))
 245             throw new Exception("expected: " + expected
 246                                 + ", got: " + contents);
 247         r.close();
 248     }
 249 
 250     // Test transferFrom asking for more bytes than remain in source
 251     @Test
 252     public void xferTest06() throws Exception { // for bug 5081340
 253         String data = "Use the source, Luke!";
 254 
 255         File source = File.createTempFile("source", null);
 256         source.deleteOnExit();
 257         File sink = File.createTempFile("sink", null);
 258         sink.deleteOnExit();
 259 
 260         FileOutputStream fos = new FileOutputStream(source);
 261         fos.write(data.getBytes("ASCII"));
 262         fos.close();
 263 
 264         FileChannel sourceChannel =
 265             new RandomAccessFile(source, "rw").getChannel();
 266         sourceChannel.position(7);
 267         long remaining = sourceChannel.size() - sourceChannel.position();
 268         FileChannel sinkChannel =
 269             new RandomAccessFile(sink, "rw").getChannel();
 270         long n = sinkChannel.transferFrom(sourceChannel, 0L,
 271                                           sourceChannel.size()); // overflow
 272         if (n != remaining)
 273             throw new Exception("n == " + n + ", remaining == " + remaining);
 274 
 275         sinkChannel.close();
 276         sourceChannel.close();
 277 
 278         checkFileData(source, data);
 279         checkFileData(sink, data.substring(7,data.length()));
 280 
 281         source.delete();
 282     }
 283 
 284     // Test transferTo to non-blocking socket channel
 285     @Test
 286     public void xferTest07() throws Exception { // for bug 5103988
 287         File source = File.createTempFile("source", null);
 288         source.deleteOnExit();
 289 
 290         FileChannel sourceChannel = new RandomAccessFile(source, "rw")
 291             .getChannel();
 292         sourceChannel.position(32000L)
 293             .write(ByteBuffer.wrap("The End".getBytes()));
 294 
 295         // The sink is a non-blocking socket channel
 296         ServerSocketChannel ssc = ServerSocketChannel.open();
 297         ssc.socket().bind(new InetSocketAddress(0));
 298         InetSocketAddress sa = new InetSocketAddress(
 299             InetAddress.getLocalHost(), ssc.socket().getLocalPort());
 300         SocketChannel sink = SocketChannel.open(sa);
 301         sink.configureBlocking(false);
 302         SocketChannel other = ssc.accept();
 303 
 304         long size = sourceChannel.size();
 305 
 306         // keep sending until congested
 307         long n;
 308         do {
 309             n = sourceChannel.transferTo(0, size, sink);
 310         } while (n > 0);
 311 
 312         sourceChannel.close();
 313         sink.close();
 314         other.close();
 315         ssc.close();
 316         source.delete();
 317     }
 318 
 319     // xferTest08() moved to TransferTo6GBFile.java
 320 
 321     // Test that transferFrom with FileChannel source that is not readable
 322     // throws NonReadableChannelException
 323     @Test
 324     public void xferTest09() throws Exception { // for bug 6984545
 325         File source = File.createTempFile("source", null);
 326         source.deleteOnExit();
 327 
 328         File target = File.createTempFile("target", null);
 329         target.deleteOnExit();
 330 
 331         FileChannel fc1 = new FileOutputStream(source).getChannel();
 332         FileChannel fc2 = new RandomAccessFile(target, "rw").getChannel();
 333         try {
 334             fc2.transferFrom(fc1, 0L, 0);
 335             throw new RuntimeException("NonReadableChannelException expected");
 336         } catch (NonReadableChannelException expected) {
 337         } finally {
 338             fc1.close();
 339             fc2.close();
 340         }
 341     }
 342 }